Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Objects/stringlib/fastsearch.h
Line
Count
Source
1
/* stringlib: fastsearch implementation */
2
3
#define STRINGLIB_FASTSEARCH_H
4
5
/* fast search/count implementation, based on a mix between boyer-
6
   moore and horspool, with a few more bells and whistles on the top.
7
   for some more background, see:
8
   https://web.archive.org/web/20201107074620/http://effbot.org/zone/stringlib.htm */
9
10
/* note: fastsearch may access s[n], which isn't a problem when using
11
   Python's ordinary string types, but may cause problems if you're
12
   using this code in other contexts.  also, the count mode returns -1
13
   if there cannot possibly be a match in the target string, and 0 if
14
   it has actually checked for matches, but didn't find any.  callers
15
   beware! */
16
17
/* If the strings are long enough, use Crochemore and Perrin's Two-Way
18
   algorithm, which has worst-case O(n) runtime and best-case O(n/k).
19
   Also compute a table of shifts to achieve O(n/k) in more cases,
20
   and often (data dependent) deduce larger shifts than pure C&P can
21
   deduce. See stringlib_find_two_way_notes.txt in this folder for a
22
   detailed explanation. */
23
24
238M
#define FAST_COUNT 0
25
97.1M
#define FAST_SEARCH 1
26
59.6M
#define FAST_RSEARCH 2
27
28
#if LONG_BIT >= 128
29
#define STRINGLIB_BLOOM_WIDTH 128
30
#elif LONG_BIT >= 64
31
905M
#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
132M
    ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
40
#define STRINGLIB_BLOOM(mask, ch)     \
41
772M
    ((mask &  (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
42
43
#ifdef STRINGLIB_FAST_MEMCHR
44
217M
#  define MEMCHR_CUT_OFF 15
45
#else
46
4.99M
#  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
222M
{
52
222M
    const STRINGLIB_CHAR *p, *e;
53
54
222M
    p = s;
55
222M
    e = s + n;
56
222M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
35.4M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
35.4M
        if (p != NULL)
60
34.0M
            return (p - s);
61
1.44M
        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
4.55M
        if (needle != 0) {
71
4.57M
            do {
72
4.57M
                const void *candidate = memchr(p, needle,
73
4.57M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
4.57M
                if (candidate == NULL)
75
19.1k
                    return -1;
76
4.55M
                s1 = p;
77
4.55M
                p = (const STRINGLIB_CHAR *)
78
4.55M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
4.55M
                if (*p == ch)
80
4.51M
                    return (p - s);
81
                /* False positive */
82
35.0k
                p++;
83
35.0k
                if (p - s1 > MEMCHR_CUT_OFF)
84
15.4k
                    continue;
85
19.6k
                if (e - p <= MEMCHR_CUT_OFF)
86
2.45k
                    break;
87
17.1k
                e1 = p + MEMCHR_CUT_OFF;
88
605k
                while (p != e1) {
89
591k
                    if (*p == ch)
90
2.82k
                        return (p - s);
91
588k
                    p++;
92
588k
                }
93
17.1k
            }
94
4.54M
            while (e - p > MEMCHR_CUT_OFF);
95
4.54M
        }
96
#endif
97
40.0M
    }
98
888M
    while (p < e) {
99
722M
        if (*p == ch)
100
16.6M
            return (p - s);
101
706M
        p++;
102
706M
    }
103
165M
    return -1;
104
182M
}
bytesobject.c:stringlib_find_char
Line
Count
Source
51
290k
{
52
290k
    const STRINGLIB_CHAR *p, *e;
53
54
290k
    p = s;
55
290k
    e = s + n;
56
290k
    if (n > MEMCHR_CUT_OFF) {
57
290k
#ifdef STRINGLIB_FAST_MEMCHR
58
290k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
290k
        if (p != NULL)
60
287k
            return (p - s);
61
3.26k
        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
290k
    }
98
90
    while (p < e) {
99
90
        if (*p == ch)
100
15
            return (p - s);
101
75
        p++;
102
75
    }
103
0
    return -1;
104
15
}
unicodeobject.c:ucs1lib_find_char
Line
Count
Source
51
196M
{
52
196M
    const STRINGLIB_CHAR *p, *e;
53
54
196M
    p = s;
55
196M
    e = s + n;
56
196M
    if (n > MEMCHR_CUT_OFF) {
57
23.8M
#ifdef STRINGLIB_FAST_MEMCHR
58
23.8M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
23.8M
        if (p != NULL)
60
22.8M
            return (p - s);
61
963k
        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
23.8M
    }
98
813M
    while (p < e) {
99
651M
        if (*p == ch)
100
10.9M
            return (p - s);
101
640M
        p++;
102
640M
    }
103
161M
    return -1;
104
172M
}
unicodeobject.c:ucs2lib_find_char
Line
Count
Source
51
4.89M
{
52
4.89M
    const STRINGLIB_CHAR *p, *e;
53
54
4.89M
    p = s;
55
4.89M
    e = s + n;
56
4.89M
    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
4.55M
        const STRINGLIB_CHAR *s1, *e1;
66
4.55M
        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
4.55M
        if (needle != 0) {
71
4.57M
            do {
72
4.57M
                const void *candidate = memchr(p, needle,
73
4.57M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
4.57M
                if (candidate == NULL)
75
19.1k
                    return -1;
76
4.55M
                s1 = p;
77
4.55M
                p = (const STRINGLIB_CHAR *)
78
4.55M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
4.55M
                if (*p == ch)
80
4.51M
                    return (p - s);
81
                /* False positive */
82
35.0k
                p++;
83
35.0k
                if (p - s1 > MEMCHR_CUT_OFF)
84
15.4k
                    continue;
85
19.6k
                if (e - p <= MEMCHR_CUT_OFF)
86
2.45k
                    break;
87
17.1k
                e1 = p + MEMCHR_CUT_OFF;
88
605k
                while (p != e1) {
89
591k
                    if (*p == ch)
90
2.82k
                        return (p - s);
91
588k
                    p++;
92
588k
                }
93
17.1k
            }
94
4.54M
            while (e - p > MEMCHR_CUT_OFF);
95
4.54M
        }
96
4.55M
#endif
97
4.55M
    }
98
5.05M
    while (p < e) {
99
4.86M
        if (*p == ch)
100
162k
            return (p - s);
101
4.70M
        p++;
102
4.70M
    }
103
189k
    return -1;
104
351k
}
unicodeobject.c:ucs4lib_find_char
Line
Count
Source
51
4.15M
{
52
4.15M
    const STRINGLIB_CHAR *p, *e;
53
54
4.15M
    p = s;
55
4.15M
    e = s + n;
56
4.15M
    if (n > MEMCHR_CUT_OFF) {
57
4.11M
#ifdef STRINGLIB_FAST_MEMCHR
58
4.11M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
4.11M
        if (p != NULL)
60
4.10M
            return (p - s);
61
11.3k
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
        const STRINGLIB_CHAR *s1, *e1;
66
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
        if (needle != 0) {
71
            do {
72
                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.11M
    }
98
182k
    while (p < e) {
99
155k
        if (*p == ch)
100
17.8k
            return (p - s);
101
137k
        p++;
102
137k
    }
103
27.2k
    return -1;
104
45.1k
}
unicodeobject.c:asciilib_find_char
Line
Count
Source
51
4.88M
{
52
4.88M
    const STRINGLIB_CHAR *p, *e;
53
54
4.88M
    p = s;
55
4.88M
    e = s + n;
56
4.88M
    if (n > MEMCHR_CUT_OFF) {
57
4.01M
#ifdef STRINGLIB_FAST_MEMCHR
58
4.01M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
4.01M
        if (p != NULL)
60
3.60M
            return (p - s);
61
409k
        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.01M
    }
98
2.76M
    while (p < e) {
99
2.71M
        if (*p == ch)
100
817k
            return (p - s);
101
1.90M
        p++;
102
1.90M
    }
103
52.5k
    return -1;
104
869k
}
bytes_methods.c:stringlib_find_char
Line
Count
Source
51
11.5M
{
52
11.5M
    const STRINGLIB_CHAR *p, *e;
53
54
11.5M
    p = s;
55
11.5M
    e = s + n;
56
11.5M
    if (n > MEMCHR_CUT_OFF) {
57
3.26M
#ifdef STRINGLIB_FAST_MEMCHR
58
3.26M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
3.26M
        if (p != NULL)
60
3.21M
            return (p - s);
61
59.2k
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
        const STRINGLIB_CHAR *s1, *e1;
66
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
        if (needle != 0) {
71
            do {
72
                const void *candidate = memchr(p, needle,
73
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
                if (candidate == NULL)
75
                    return -1;
76
                s1 = p;
77
                p = (const STRINGLIB_CHAR *)
78
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
                if (*p == ch)
80
                    return (p - s);
81
                /* False positive */
82
                p++;
83
                if (p - s1 > MEMCHR_CUT_OFF)
84
                    continue;
85
                if (e - p <= MEMCHR_CUT_OFF)
86
                    break;
87
                e1 = p + MEMCHR_CUT_OFF;
88
                while (p != e1) {
89
                    if (*p == ch)
90
                        return (p - s);
91
                    p++;
92
                }
93
            }
94
            while (e - p > MEMCHR_CUT_OFF);
95
        }
96
#endif
97
3.26M
    }
98
67.0M
    while (p < e) {
99
63.4M
        if (*p == ch)
100
4.66M
            return (p - s);
101
58.7M
        p++;
102
58.7M
    }
103
3.63M
    return -1;
104
8.29M
}
Unexecuted instantiation: bytearrayobject.c:stringlib_find_char
105
106
#undef MEMCHR_CUT_OFF
107
108
#if STRINGLIB_SIZEOF_CHAR == 1
109
1.50M
#  define MEMRCHR_CUT_OFF 15
110
#else
111
154k
#  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
1.63M
{
118
1.63M
    const STRINGLIB_CHAR *p;
119
1.63M
#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.63M
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
200k
        if (p != NULL)
129
111k
            return (p - s);
130
88.3k
        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
123k
        if (needle != 0) {
141
130k
            do {
142
130k
                void *candidate = memrchr(s, needle,
143
130k
                                          n * sizeof(STRINGLIB_CHAR));
144
130k
                if (candidate == NULL)
145
1.17k
                    return -1;
146
129k
                n1 = n;
147
129k
                p = (const STRINGLIB_CHAR *)
148
129k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
129k
                n = p - s;
150
129k
                if (*p == ch)
151
121k
                    return n;
152
                /* False positive */
153
7.90k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
4.33k
                    continue;
155
3.57k
                if (n <= MEMRCHR_CUT_OFF)
156
60
                    break;
157
3.51k
                s1 = p - MEMRCHR_CUT_OFF;
158
138k
                while (p > s1) {
159
135k
                    p--;
160
135k
                    if (*p == ch)
161
227
                        return (p - s);
162
135k
                }
163
3.29k
                n = p - s;
164
3.29k
            }
165
123k
            while (n > MEMRCHR_CUT_OFF);
166
123k
        }
167
#endif
168
323k
    }
169
1.30M
#endif  /* HAVE_MEMRCHR */
170
1.30M
    p = s + n;
171
6.94M
    while (p > s) {
172
6.04M
        p--;
173
6.04M
        if (*p == ch)
174
413k
            return (p - s);
175
6.04M
    }
176
895k
    return -1;
177
1.30M
}
Unexecuted instantiation: bytesobject.c:stringlib_rfind_char
unicodeobject.c:ucs1lib_rfind_char
Line
Count
Source
117
56.6k
{
118
56.6k
    const STRINGLIB_CHAR *p;
119
56.6k
#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
56.6k
    if (n > MEMRCHR_CUT_OFF) {
126
48.4k
#if STRINGLIB_SIZEOF_CHAR == 1
127
48.4k
        p = memrchr(s, ch, n);
128
48.4k
        if (p != NULL)
129
46.6k
            return (p - s);
130
1.72k
        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
48.4k
    }
169
8.23k
#endif  /* HAVE_MEMRCHR */
170
8.23k
    p = s + n;
171
47.0k
    while (p > s) {
172
39.5k
        p--;
173
39.5k
        if (*p == ch)
174
678
            return (p - s);
175
39.5k
    }
176
7.55k
    return -1;
177
8.23k
}
unicodeobject.c:ucs2lib_rfind_char
Line
Count
Source
117
121k
{
118
121k
    const STRINGLIB_CHAR *p;
119
121k
#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
121k
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
        if (p != NULL)
129
            return (p - s);
130
        return -1;
131
#else
132
        /* use memrchr if we can choose a needle without too many likely
133
           false positives */
134
115k
        const STRINGLIB_CHAR *s1;
135
115k
        Py_ssize_t n1;
136
115k
        unsigned char needle = ch & 0xff;
137
        /* If looking for a multiple of 256, we'd have too
138
           many false positives looking for the '\0' byte in UCS2
139
           and UCS4 representations. */
140
115k
        if (needle != 0) {
141
120k
            do {
142
120k
                void *candidate = memrchr(s, needle,
143
120k
                                          n * sizeof(STRINGLIB_CHAR));
144
120k
                if (candidate == NULL)
145
718
                    return -1;
146
119k
                n1 = n;
147
119k
                p = (const STRINGLIB_CHAR *)
148
119k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
119k
                n = p - s;
150
119k
                if (*p == ch)
151
114k
                    return n;
152
                /* False positive */
153
4.72k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
3.02k
                    continue;
155
1.70k
                if (n <= MEMRCHR_CUT_OFF)
156
34
                    break;
157
1.67k
                s1 = p - MEMRCHR_CUT_OFF;
158
65.4k
                while (p > s1) {
159
63.9k
                    p--;
160
63.9k
                    if (*p == ch)
161
108
                        return (p - s);
162
63.9k
                }
163
1.56k
                n = p - s;
164
1.56k
            }
165
115k
            while (n > MEMRCHR_CUT_OFF);
166
115k
        }
167
115k
#endif
168
115k
    }
169
6.34k
#endif  /* HAVE_MEMRCHR */
170
6.34k
    p = s + n;
171
31.5k
    while (p > s) {
172
30.2k
        p--;
173
30.2k
        if (*p == ch)
174
5.06k
            return (p - s);
175
30.2k
    }
176
1.27k
    return -1;
177
6.34k
}
unicodeobject.c:ucs4lib_rfind_char
Line
Count
Source
117
9.95k
{
118
9.95k
    const STRINGLIB_CHAR *p;
119
9.95k
#ifdef HAVE_MEMRCHR
120
    /* memrchr() is a GNU extension, available since glibc 2.1.91.  it
121
       doesn't seem as optimized as memchr(), but is still quite
122
       faster than our hand-written loop below. There is no wmemrchr
123
       for 4-byte chars. */
124
125
9.95k
    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
7.74k
        const STRINGLIB_CHAR *s1;
135
7.74k
        Py_ssize_t n1;
136
7.74k
        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
7.74k
        if (needle != 0) {
141
10.7k
            do {
142
10.7k
                void *candidate = memrchr(s, needle,
143
10.7k
                                          n * sizeof(STRINGLIB_CHAR));
144
10.7k
                if (candidate == NULL)
145
461
                    return -1;
146
10.2k
                n1 = n;
147
10.2k
                p = (const STRINGLIB_CHAR *)
148
10.2k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
10.2k
                n = p - s;
150
10.2k
                if (*p == ch)
151
7.06k
                    return n;
152
                /* False positive */
153
3.18k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
1.31k
                    continue;
155
1.87k
                if (n <= MEMRCHR_CUT_OFF)
156
26
                    break;
157
1.84k
                s1 = p - MEMRCHR_CUT_OFF;
158
72.9k
                while (p > s1) {
159
71.1k
                    p--;
160
71.1k
                    if (*p == ch)
161
119
                        return (p - s);
162
71.1k
                }
163
1.72k
                n = p - s;
164
1.72k
            }
165
7.74k
            while (n > MEMRCHR_CUT_OFF);
166
7.74k
        }
167
7.74k
#endif
168
7.74k
    }
169
2.30k
#endif  /* HAVE_MEMRCHR */
170
2.30k
    p = s + n;
171
18.6k
    while (p > s) {
172
17.6k
        p--;
173
17.6k
        if (*p == ch)
174
1.21k
            return (p - s);
175
17.6k
    }
176
1.09k
    return -1;
177
2.30k
}
unicodeobject.c:asciilib_rfind_char
Line
Count
Source
117
62.0k
{
118
62.0k
    const STRINGLIB_CHAR *p;
119
62.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
62.0k
    if (n > MEMRCHR_CUT_OFF) {
126
21.3k
#if STRINGLIB_SIZEOF_CHAR == 1
127
21.3k
        p = memrchr(s, ch, n);
128
21.3k
        if (p != NULL)
129
20.9k
            return (p - s);
130
401
        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
21.3k
    }
169
40.7k
#endif  /* HAVE_MEMRCHR */
170
40.7k
    p = s + n;
171
243k
    while (p > s) {
172
214k
        p--;
173
214k
        if (*p == ch)
174
11.8k
            return (p - s);
175
214k
    }
176
28.8k
    return -1;
177
40.7k
}
bytes_methods.c:stringlib_rfind_char
Line
Count
Source
117
1.38M
{
118
1.38M
    const STRINGLIB_CHAR *p;
119
1.38M
#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.38M
    if (n > MEMRCHR_CUT_OFF) {
126
130k
#if STRINGLIB_SIZEOF_CHAR == 1
127
130k
        p = memrchr(s, ch, n);
128
130k
        if (p != NULL)
129
44.3k
            return (p - s);
130
86.1k
        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
130k
    }
169
1.25M
#endif  /* HAVE_MEMRCHR */
170
1.25M
    p = s + n;
171
6.60M
    while (p > s) {
172
5.74M
        p--;
173
5.74M
        if (*p == ch)
174
394k
            return (p - s);
175
5.74M
    }
176
857k
    return -1;
177
1.25M
}
Unexecuted instantiation: bytearrayobject.c:stringlib_rfind_char
178
179
#undef MEMRCHR_CUT_OFF
180
181
/* Change to a 1 to see logging comments walk through the algorithm. */
182
#if 0 && STRINGLIB_SIZEOF_CHAR == 1
183
# define LOG(...) printf(__VA_ARGS__)
184
# define LOG_STRING(s, n) printf("\"%.*s\"", (int)(n), s)
185
# define LOG_LINEUP() do {                                         \
186
    LOG("> "); LOG_STRING(haystack, len_haystack); LOG("\n> ");    \
187
    LOG("%*s",(int)(window_last - haystack + 1 - len_needle), ""); \
188
    LOG_STRING(needle, len_needle); LOG("\n");                     \
189
} while(0)
190
#else
191
# define LOG(...)
192
# define LOG_STRING(s, n)
193
# define LOG_LINEUP()
194
#endif
195
196
Py_LOCAL_INLINE(Py_ssize_t)
197
STRINGLIB(_lex_search)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle,
198
                       Py_ssize_t *return_period, int invert_alphabet)
199
44
{
200
    /* Do a lexicographic search. Essentially this:
201
           >>> max(needle[i:] for i in range(len(needle)+1))
202
       Also find the period of the right half.   */
203
44
    Py_ssize_t max_suffix = 0;
204
44
    Py_ssize_t candidate = 1;
205
44
    Py_ssize_t k = 0;
206
    // The period of the right half.
207
44
    Py_ssize_t period = 1;
208
209
440
    while (candidate + k < len_needle) {
210
        // each loop increases candidate + k + max_suffix
211
396
        STRINGLIB_CHAR a = needle[candidate + k];
212
396
        STRINGLIB_CHAR b = needle[max_suffix + k];
213
        // check if the suffix at candidate is better than max_suffix
214
396
        if (invert_alphabet ? (b < a) : (a < b)) {
215
            // Fell short of max_suffix.
216
            // The next k + 1 characters are non-increasing
217
            // from candidate, so they won't start a maximal suffix.
218
286
            candidate += k + 1;
219
286
            k = 0;
220
            // We've ruled out any period smaller than what's
221
            // been scanned since max_suffix.
222
286
            period = candidate - max_suffix;
223
286
        }
224
110
        else if (a == b) {
225
22
            if (k + 1 != period) {
226
                // Keep scanning the equal strings
227
0
                k++;
228
0
            }
229
22
            else {
230
                // Matched a whole period.
231
                // Start matching the next period.
232
22
                candidate += period;
233
22
                k = 0;
234
22
            }
235
22
        }
236
88
        else {
237
            // Did better than max_suffix, so replace it.
238
88
            max_suffix = candidate;
239
88
            candidate++;
240
88
            k = 0;
241
88
            period = 1;
242
88
        }
243
396
    }
244
44
    *return_period = period;
245
44
    return max_suffix;
246
44
}
Unexecuted instantiation: bytesobject.c:stringlib__lex_search
Unexecuted instantiation: unicodeobject.c:asciilib__lex_search
unicodeobject.c:ucs1lib__lex_search
Line
Count
Source
199
44
{
200
    /* Do a lexicographic search. Essentially this:
201
           >>> max(needle[i:] for i in range(len(needle)+1))
202
       Also find the period of the right half.   */
203
44
    Py_ssize_t max_suffix = 0;
204
44
    Py_ssize_t candidate = 1;
205
44
    Py_ssize_t k = 0;
206
    // The period of the right half.
207
44
    Py_ssize_t period = 1;
208
209
440
    while (candidate + k < len_needle) {
210
        // each loop increases candidate + k + max_suffix
211
396
        STRINGLIB_CHAR a = needle[candidate + k];
212
396
        STRINGLIB_CHAR b = needle[max_suffix + k];
213
        // check if the suffix at candidate is better than max_suffix
214
396
        if (invert_alphabet ? (b < a) : (a < b)) {
215
            // Fell short of max_suffix.
216
            // The next k + 1 characters are non-increasing
217
            // from candidate, so they won't start a maximal suffix.
218
286
            candidate += k + 1;
219
286
            k = 0;
220
            // We've ruled out any period smaller than what's
221
            // been scanned since max_suffix.
222
286
            period = candidate - max_suffix;
223
286
        }
224
110
        else if (a == b) {
225
22
            if (k + 1 != period) {
226
                // Keep scanning the equal strings
227
0
                k++;
228
0
            }
229
22
            else {
230
                // Matched a whole period.
231
                // Start matching the next period.
232
22
                candidate += period;
233
22
                k = 0;
234
22
            }
235
22
        }
236
88
        else {
237
            // Did better than max_suffix, so replace it.
238
88
            max_suffix = candidate;
239
88
            candidate++;
240
88
            k = 0;
241
88
            period = 1;
242
88
        }
243
396
    }
244
44
    *return_period = period;
245
44
    return max_suffix;
246
44
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__lex_search
Unexecuted instantiation: unicodeobject.c:ucs4lib__lex_search
Unexecuted instantiation: bytes_methods.c:stringlib__lex_search
Unexecuted instantiation: bytearrayobject.c:stringlib__lex_search
247
248
Py_LOCAL_INLINE(Py_ssize_t)
249
STRINGLIB(_factorize)(const STRINGLIB_CHAR *needle,
250
                      Py_ssize_t len_needle,
251
                      Py_ssize_t *return_period)
252
22
{
253
    /* Do a "critical factorization", making it so that:
254
       >>> needle = (left := needle[:cut]) + (right := needle[cut:])
255
       where the "local period" of the cut is maximal.
256
257
       The local period of the cut is the minimal length of a string w
258
       such that (left endswith w or w endswith left)
259
       and (right startswith w or w startswith right).
260
261
       The Critical Factorization Theorem says that this maximal local
262
       period is the global period of the string.
263
264
       Crochemore and Perrin (1991) show that this cut can be computed
265
       as the later of two cuts: one that gives a lexicographically
266
       maximal right half, and one that gives the same with the
267
       with respect to a reversed alphabet-ordering.
268
269
       This is what we want to happen:
270
           >>> x = "GCAGAGAG"
271
           >>> cut, period = factorize(x)
272
           >>> x[:cut], (right := x[cut:])
273
           ('GC', 'AGAGAG')
274
           >>> period  # right half period
275
           2
276
           >>> right[period:] == right[:-period]
277
           True
278
279
       This is how the local period lines up in the above example:
280
                GC | AGAGAG
281
           AGAGAGC = AGAGAGC
282
       The length of this minimal repetition is 7, which is indeed the
283
       period of the original string. */
284
285
22
    Py_ssize_t cut1, period1, cut2, period2, cut, period;
286
22
    cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0);
287
22
    cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1);
288
289
    // Take the later cut.
290
22
    if (cut1 > cut2) {
291
22
        period = period1;
292
22
        cut = cut1;
293
22
    }
294
0
    else {
295
0
        period = period2;
296
0
        cut = cut2;
297
0
    }
298
299
22
    LOG("split: "); LOG_STRING(needle, cut);
300
22
    LOG(" + "); LOG_STRING(needle + cut, len_needle - cut);
301
22
    LOG("\n");
302
303
22
    *return_period = period;
304
22
    return cut;
305
22
}
Unexecuted instantiation: bytesobject.c:stringlib__factorize
Unexecuted instantiation: unicodeobject.c:asciilib__factorize
unicodeobject.c:ucs1lib__factorize
Line
Count
Source
252
22
{
253
    /* Do a "critical factorization", making it so that:
254
       >>> needle = (left := needle[:cut]) + (right := needle[cut:])
255
       where the "local period" of the cut is maximal.
256
257
       The local period of the cut is the minimal length of a string w
258
       such that (left endswith w or w endswith left)
259
       and (right startswith w or w startswith right).
260
261
       The Critical Factorization Theorem says that this maximal local
262
       period is the global period of the string.
263
264
       Crochemore and Perrin (1991) show that this cut can be computed
265
       as the later of two cuts: one that gives a lexicographically
266
       maximal right half, and one that gives the same with the
267
       with respect to a reversed alphabet-ordering.
268
269
       This is what we want to happen:
270
           >>> x = "GCAGAGAG"
271
           >>> cut, period = factorize(x)
272
           >>> x[:cut], (right := x[cut:])
273
           ('GC', 'AGAGAG')
274
           >>> period  # right half period
275
           2
276
           >>> right[period:] == right[:-period]
277
           True
278
279
       This is how the local period lines up in the above example:
280
                GC | AGAGAG
281
           AGAGAGC = AGAGAGC
282
       The length of this minimal repetition is 7, which is indeed the
283
       period of the original string. */
284
285
22
    Py_ssize_t cut1, period1, cut2, period2, cut, period;
286
22
    cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0);
287
22
    cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1);
288
289
    // Take the later cut.
290
22
    if (cut1 > cut2) {
291
22
        period = period1;
292
22
        cut = cut1;
293
22
    }
294
0
    else {
295
0
        period = period2;
296
0
        cut = cut2;
297
0
    }
298
299
22
    LOG("split: "); LOG_STRING(needle, cut);
300
22
    LOG(" + "); LOG_STRING(needle + cut, len_needle - cut);
301
22
    LOG("\n");
302
303
22
    *return_period = period;
304
22
    return cut;
305
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__factorize
Unexecuted instantiation: unicodeobject.c:ucs4lib__factorize
Unexecuted instantiation: bytes_methods.c:stringlib__factorize
Unexecuted instantiation: bytearrayobject.c:stringlib__factorize
306
307
308
242
#define SHIFT_TYPE uint8_t
309
#define MAX_SHIFT UINT8_MAX
310
311
79.7k
#define TABLE_SIZE_BITS 6u
312
79.7k
#define TABLE_SIZE (1U << TABLE_SIZE_BITS)
313
78.3k
#define TABLE_MASK (TABLE_SIZE - 1U)
314
315
typedef struct STRINGLIB(_pre) {
316
    const STRINGLIB_CHAR *needle;
317
    Py_ssize_t len_needle;
318
    Py_ssize_t cut;
319
    Py_ssize_t period;
320
    Py_ssize_t gap;
321
    int is_periodic;
322
    SHIFT_TYPE table[TABLE_SIZE];
323
} STRINGLIB(prework);
324
325
326
static void
327
STRINGLIB(_preprocess)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle,
328
                       STRINGLIB(prework) *p)
329
22
{
330
22
    p->needle = needle;
331
22
    p->len_needle = len_needle;
332
22
    p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period));
333
22
    assert(p->period + p->cut <= len_needle);
334
22
    p->is_periodic = (0 == memcmp(needle,
335
22
                                  needle + p->period,
336
22
                                  p->cut * STRINGLIB_SIZEOF_CHAR));
337
22
    if (p->is_periodic) {
338
0
        assert(p->cut <= len_needle/2);
339
0
        assert(p->cut < p->period);
340
0
    }
341
22
    else {
342
        // A lower bound on the period
343
22
        p->period = Py_MAX(p->cut, len_needle - p->cut) + 1;
344
22
    }
345
    // The gap between the last character and the previous
346
    // occurrence of an equivalent character (modulo TABLE_SIZE)
347
22
    p->gap = len_needle;
348
22
    STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK;
349
154
    for (Py_ssize_t i = len_needle - 2; i >= 0; i--) {
350
154
        STRINGLIB_CHAR x = needle[i] & TABLE_MASK;
351
154
        if (x == last) {
352
22
            p->gap = len_needle - 1 - i;
353
22
            break;
354
22
        }
355
154
    }
356
    // Fill up a compressed Boyer-Moore "Bad Character" table
357
22
    Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT);
358
1.43k
    for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) {
359
1.40k
        p->table[i] = Py_SAFE_DOWNCAST(not_found_shift,
360
1.40k
                                       Py_ssize_t, SHIFT_TYPE);
361
1.40k
    }
362
242
    for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) {
363
220
        SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i,
364
220
                                            Py_ssize_t, SHIFT_TYPE);
365
220
        p->table[needle[i] & TABLE_MASK] = shift;
366
220
    }
367
22
}
Unexecuted instantiation: bytesobject.c:stringlib__preprocess
Unexecuted instantiation: unicodeobject.c:asciilib__preprocess
unicodeobject.c:ucs1lib__preprocess
Line
Count
Source
329
22
{
330
22
    p->needle = needle;
331
22
    p->len_needle = len_needle;
332
22
    p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period));
333
22
    assert(p->period + p->cut <= len_needle);
334
22
    p->is_periodic = (0 == memcmp(needle,
335
22
                                  needle + p->period,
336
22
                                  p->cut * STRINGLIB_SIZEOF_CHAR));
337
22
    if (p->is_periodic) {
338
0
        assert(p->cut <= len_needle/2);
339
0
        assert(p->cut < p->period);
340
0
    }
341
22
    else {
342
        // A lower bound on the period
343
22
        p->period = Py_MAX(p->cut, len_needle - p->cut) + 1;
344
22
    }
345
    // The gap between the last character and the previous
346
    // occurrence of an equivalent character (modulo TABLE_SIZE)
347
22
    p->gap = len_needle;
348
22
    STRINGLIB_CHAR last = needle[len_needle - 1] & TABLE_MASK;
349
154
    for (Py_ssize_t i = len_needle - 2; i >= 0; i--) {
350
154
        STRINGLIB_CHAR x = needle[i] & TABLE_MASK;
351
154
        if (x == last) {
352
22
            p->gap = len_needle - 1 - i;
353
22
            break;
354
22
        }
355
154
    }
356
    // Fill up a compressed Boyer-Moore "Bad Character" table
357
22
    Py_ssize_t not_found_shift = Py_MIN(len_needle, MAX_SHIFT);
358
1.43k
    for (Py_ssize_t i = 0; i < (Py_ssize_t)TABLE_SIZE; i++) {
359
1.40k
        p->table[i] = Py_SAFE_DOWNCAST(not_found_shift,
360
1.40k
                                       Py_ssize_t, SHIFT_TYPE);
361
1.40k
    }
362
242
    for (Py_ssize_t i = len_needle - not_found_shift; i < len_needle; i++) {
363
220
        SHIFT_TYPE shift = Py_SAFE_DOWNCAST(len_needle - 1 - i,
364
220
                                            Py_ssize_t, SHIFT_TYPE);
365
220
        p->table[needle[i] & TABLE_MASK] = shift;
366
220
    }
367
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__preprocess
Unexecuted instantiation: unicodeobject.c:ucs4lib__preprocess
Unexecuted instantiation: bytes_methods.c:stringlib__preprocess
Unexecuted instantiation: bytearrayobject.c:stringlib__preprocess
368
369
static Py_ssize_t
370
STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack,
371
                    STRINGLIB(prework) *p)
372
22
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
22
    const Py_ssize_t len_needle = p->len_needle;
376
22
    const Py_ssize_t cut = p->cut;
377
22
    Py_ssize_t period = p->period;
378
22
    const STRINGLIB_CHAR *const needle = p->needle;
379
22
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
22
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
22
    SHIFT_TYPE *table = p->table;
382
22
    const STRINGLIB_CHAR *window;
383
22
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
22
    Py_ssize_t gap = p->gap;
386
22
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
22
    if (p->is_periodic) {
388
0
        LOG("Needle is periodic.\n");
389
0
        Py_ssize_t memory = 0;
390
0
      periodicwindowloop:
391
0
        while (window_last < haystack_end) {
392
0
            assert(memory == 0);
393
0
            for (;;) {
394
0
                LOG_LINEUP();
395
0
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
396
0
                window_last += shift;
397
0
                if (shift == 0) {
398
0
                    break;
399
0
                }
400
0
                if (window_last >= haystack_end) {
401
0
                    return -1;
402
0
                }
403
0
                LOG("Horspool skip\n");
404
0
            }
405
0
          no_shift:
406
0
            window = window_last - len_needle + 1;
407
0
            assert((window[len_needle - 1] & TABLE_MASK) ==
408
0
                   (needle[len_needle - 1] & TABLE_MASK));
409
0
            Py_ssize_t i = Py_MAX(cut, memory);
410
0
            for (; i < len_needle; i++) {
411
0
                if (needle[i] != window[i]) {
412
0
                    if (i < gap_jump_end) {
413
0
                        LOG("Early right half mismatch: jump by gap.\n");
414
0
                        assert(gap >= i - cut + 1);
415
0
                        window_last += gap;
416
0
                    }
417
0
                    else {
418
0
                        LOG("Late right half mismatch: jump by n (>gap)\n");
419
0
                        assert(i - cut + 1 > gap);
420
0
                        window_last += i - cut + 1;
421
0
                    }
422
0
                    memory = 0;
423
0
                    goto periodicwindowloop;
424
0
                }
425
0
            }
426
0
            for (i = memory; i < cut; i++) {
427
0
                if (needle[i] != window[i]) {
428
0
                    LOG("Left half does not match.\n");
429
0
                    window_last += period;
430
0
                    memory = len_needle - period;
431
0
                    if (window_last >= haystack_end) {
432
0
                        return -1;
433
0
                    }
434
0
                    Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
435
0
                    if (shift) {
436
                        // A mismatch has been identified to the right
437
                        // of where i will next start, so we can jump
438
                        // at least as far as if the mismatch occurred
439
                        // on the first comparison.
440
0
                        Py_ssize_t mem_jump = Py_MAX(cut, memory) - cut + 1;
441
0
                        LOG("Skip with Memory.\n");
442
0
                        memory = 0;
443
0
                        window_last += Py_MAX(shift, mem_jump);
444
0
                        goto periodicwindowloop;
445
0
                    }
446
0
                    goto no_shift;
447
0
                }
448
0
            }
449
0
            LOG("Found a match!\n");
450
0
            return window - haystack;
451
0
        }
452
0
    }
453
22
    else {
454
22
        period = Py_MAX(gap, period);
455
22
        LOG("Needle is not periodic.\n");
456
16.9k
      windowloop:
457
16.9k
        while (window_last < haystack_end) {
458
77.9k
            for (;;) {
459
77.9k
                LOG_LINEUP();
460
77.9k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
77.9k
                window_last += shift;
462
77.9k
                if (shift == 0) {
463
16.9k
                    break;
464
16.9k
                }
465
60.9k
                if (window_last >= haystack_end) {
466
19
                    return -1;
467
19
                }
468
60.9k
                LOG("Horspool skip\n");
469
60.9k
            }
470
16.9k
            window = window_last - len_needle + 1;
471
16.9k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
16.9k
                   (needle[len_needle - 1] & TABLE_MASK));
473
16.9k
            Py_ssize_t i = cut;
474
17.1k
            for (; i < len_needle; i++) {
475
17.0k
                if (needle[i] != window[i]) {
476
16.8k
                    if (i < gap_jump_end) {
477
16.8k
                        LOG("Early right half mismatch: jump by gap.\n");
478
16.8k
                        assert(gap >= i - cut + 1);
479
16.8k
                        window_last += gap;
480
16.8k
                    }
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
16.8k
                    goto windowloop;
487
16.8k
                }
488
17.0k
            }
489
262
            for (Py_ssize_t i = 0; i < cut; i++) {
490
260
                if (needle[i] != window[i]) {
491
104
                    LOG("Left half does not match.\n");
492
104
                    window_last += period;
493
104
                    goto windowloop;
494
104
                }
495
260
            }
496
2
            LOG("Found a match!\n");
497
2
            return window - haystack;
498
106
        }
499
16.9k
    }
500
1
    LOG("Not found. Returning -1.\n");
501
1
    return -1;
502
22
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way
Unexecuted instantiation: unicodeobject.c:asciilib__two_way
unicodeobject.c:ucs1lib__two_way
Line
Count
Source
372
22
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
22
    const Py_ssize_t len_needle = p->len_needle;
376
22
    const Py_ssize_t cut = p->cut;
377
22
    Py_ssize_t period = p->period;
378
22
    const STRINGLIB_CHAR *const needle = p->needle;
379
22
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
22
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
22
    SHIFT_TYPE *table = p->table;
382
22
    const STRINGLIB_CHAR *window;
383
22
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
22
    Py_ssize_t gap = p->gap;
386
22
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
22
    if (p->is_periodic) {
388
0
        LOG("Needle is periodic.\n");
389
0
        Py_ssize_t memory = 0;
390
0
      periodicwindowloop:
391
0
        while (window_last < haystack_end) {
392
0
            assert(memory == 0);
393
0
            for (;;) {
394
0
                LOG_LINEUP();
395
0
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
396
0
                window_last += shift;
397
0
                if (shift == 0) {
398
0
                    break;
399
0
                }
400
0
                if (window_last >= haystack_end) {
401
0
                    return -1;
402
0
                }
403
0
                LOG("Horspool skip\n");
404
0
            }
405
0
          no_shift:
406
0
            window = window_last - len_needle + 1;
407
0
            assert((window[len_needle - 1] & TABLE_MASK) ==
408
0
                   (needle[len_needle - 1] & TABLE_MASK));
409
0
            Py_ssize_t i = Py_MAX(cut, memory);
410
0
            for (; i < len_needle; i++) {
411
0
                if (needle[i] != window[i]) {
412
0
                    if (i < gap_jump_end) {
413
0
                        LOG("Early right half mismatch: jump by gap.\n");
414
0
                        assert(gap >= i - cut + 1);
415
0
                        window_last += gap;
416
0
                    }
417
0
                    else {
418
0
                        LOG("Late right half mismatch: jump by n (>gap)\n");
419
0
                        assert(i - cut + 1 > gap);
420
0
                        window_last += i - cut + 1;
421
0
                    }
422
0
                    memory = 0;
423
0
                    goto periodicwindowloop;
424
0
                }
425
0
            }
426
0
            for (i = memory; i < cut; i++) {
427
0
                if (needle[i] != window[i]) {
428
0
                    LOG("Left half does not match.\n");
429
0
                    window_last += period;
430
0
                    memory = len_needle - period;
431
0
                    if (window_last >= haystack_end) {
432
0
                        return -1;
433
0
                    }
434
0
                    Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
435
0
                    if (shift) {
436
                        // A mismatch has been identified to the right
437
                        // of where i will next start, so we can jump
438
                        // at least as far as if the mismatch occurred
439
                        // on the first comparison.
440
0
                        Py_ssize_t mem_jump = Py_MAX(cut, memory) - cut + 1;
441
0
                        LOG("Skip with Memory.\n");
442
0
                        memory = 0;
443
0
                        window_last += Py_MAX(shift, mem_jump);
444
0
                        goto periodicwindowloop;
445
0
                    }
446
0
                    goto no_shift;
447
0
                }
448
0
            }
449
0
            LOG("Found a match!\n");
450
0
            return window - haystack;
451
0
        }
452
0
    }
453
22
    else {
454
22
        period = Py_MAX(gap, period);
455
22
        LOG("Needle is not periodic.\n");
456
16.9k
      windowloop:
457
16.9k
        while (window_last < haystack_end) {
458
77.9k
            for (;;) {
459
77.9k
                LOG_LINEUP();
460
77.9k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
77.9k
                window_last += shift;
462
77.9k
                if (shift == 0) {
463
16.9k
                    break;
464
16.9k
                }
465
60.9k
                if (window_last >= haystack_end) {
466
19
                    return -1;
467
19
                }
468
60.9k
                LOG("Horspool skip\n");
469
60.9k
            }
470
16.9k
            window = window_last - len_needle + 1;
471
16.9k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
16.9k
                   (needle[len_needle - 1] & TABLE_MASK));
473
16.9k
            Py_ssize_t i = cut;
474
17.1k
            for (; i < len_needle; i++) {
475
17.0k
                if (needle[i] != window[i]) {
476
16.8k
                    if (i < gap_jump_end) {
477
16.8k
                        LOG("Early right half mismatch: jump by gap.\n");
478
16.8k
                        assert(gap >= i - cut + 1);
479
16.8k
                        window_last += gap;
480
16.8k
                    }
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
16.8k
                    goto windowloop;
487
16.8k
                }
488
17.0k
            }
489
262
            for (Py_ssize_t i = 0; i < cut; i++) {
490
260
                if (needle[i] != window[i]) {
491
104
                    LOG("Left half does not match.\n");
492
104
                    window_last += period;
493
104
                    goto windowloop;
494
104
                }
495
260
            }
496
2
            LOG("Found a match!\n");
497
2
            return window - haystack;
498
106
        }
499
16.9k
    }
500
1
    LOG("Not found. Returning -1.\n");
501
1
    return -1;
502
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way
Unexecuted instantiation: bytes_methods.c:stringlib__two_way
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way
503
504
505
static Py_ssize_t
506
STRINGLIB(_two_way_find)(const STRINGLIB_CHAR *haystack,
507
                         Py_ssize_t len_haystack,
508
                         const STRINGLIB_CHAR *needle,
509
                         Py_ssize_t len_needle)
510
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way_find
Unexecuted instantiation: unicodeobject.c:asciilib__two_way_find
unicodeobject.c:ucs1lib__two_way_find
Line
Count
Source
510
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_find
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_find
Unexecuted instantiation: bytes_methods.c:stringlib__two_way_find
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_find
516
517
518
static Py_ssize_t
519
STRINGLIB(_two_way_count)(const STRINGLIB_CHAR *haystack,
520
                          Py_ssize_t len_haystack,
521
                          const STRINGLIB_CHAR *needle,
522
                          Py_ssize_t len_needle,
523
                          Py_ssize_t maxcount)
524
0
{
525
0
    LOG("###### Counting \"%s\" in \"%s\".\n", needle, haystack);
526
0
    STRINGLIB(prework) p;
527
0
    STRINGLIB(_preprocess)(needle, len_needle, &p);
528
0
    Py_ssize_t index = 0, count = 0;
529
0
    while (1) {
530
0
        Py_ssize_t result;
531
0
        result = STRINGLIB(_two_way)(haystack + index,
532
0
                                     len_haystack - index, &p);
533
0
        if (result == -1) {
534
0
            return count;
535
0
        }
536
0
        count++;
537
0
        if (count == maxcount) {
538
0
            return maxcount;
539
0
        }
540
0
        index += result + len_needle;
541
0
    }
542
0
    return count;
543
0
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way_count
Unexecuted instantiation: unicodeobject.c:asciilib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs1lib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_count
Unexecuted instantiation: bytes_methods.c:stringlib__two_way_count
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_count
544
545
#undef SHIFT_TYPE
546
#undef NOT_FOUND
547
#undef SHIFT_OVERFLOW
548
#undef TABLE_SIZE_BITS
549
#undef TABLE_SIZE
550
#undef TABLE_MASK
551
552
#undef LOG
553
#undef LOG_STRING
554
#undef LOG_LINEUP
555
556
static inline Py_ssize_t
557
STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
558
                        const STRINGLIB_CHAR* p, Py_ssize_t m,
559
                        Py_ssize_t maxcount, int mode)
560
31.6M
{
561
31.6M
    const Py_ssize_t w = n - m;
562
31.6M
    Py_ssize_t mlast = m - 1, count = 0;
563
31.6M
    Py_ssize_t gap = mlast;
564
31.6M
    const STRINGLIB_CHAR last = p[mlast];
565
31.6M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
31.6M
    unsigned long mask = 0;
568
132M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
101M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
101M
        if (p[i] == last) {
571
2.14M
            gap = mlast - i - 1;
572
2.14M
        }
573
101M
    }
574
31.6M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
819M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
801M
        if (ss[i] == last) {
578
            /* candidate match */
579
49.2M
            Py_ssize_t j;
580
76.8M
            for (j = 0; j < mlast; j++) {
581
49.4M
                if (s[i+j] != p[j]) {
582
21.8M
                    break;
583
21.8M
                }
584
49.4M
            }
585
49.2M
            if (j == mlast) {
586
                /* got a match! */
587
27.3M
                if (mode != FAST_COUNT) {
588
13.7M
                    return i;
589
13.7M
                }
590
13.6M
                count++;
591
13.6M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
13.6M
                i = i + mlast;
595
13.6M
                continue;
596
13.6M
            }
597
            /* miss: check if next character is part of pattern */
598
21.8M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
4.39M
                i = i + m;
600
4.39M
            }
601
17.4M
            else {
602
17.4M
                i = i + gap;
603
17.4M
            }
604
21.8M
        }
605
752M
        else {
606
            /* skip: check if next character is part of pattern */
607
752M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
675M
                i = i + m;
609
675M
            }
610
752M
        }
611
801M
    }
612
17.8M
    return mode == FAST_COUNT ? count : -1;
613
31.6M
}
Unexecuted instantiation: bytesobject.c:stringlib_default_find
unicodeobject.c:asciilib_default_find
Line
Count
Source
560
3.18M
{
561
3.18M
    const Py_ssize_t w = n - m;
562
3.18M
    Py_ssize_t mlast = m - 1, count = 0;
563
3.18M
    Py_ssize_t gap = mlast;
564
3.18M
    const STRINGLIB_CHAR last = p[mlast];
565
3.18M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
3.18M
    unsigned long mask = 0;
568
6.36M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.18M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.18M
        if (p[i] == last) {
571
4.69k
            gap = mlast - i - 1;
572
4.69k
        }
573
3.18M
    }
574
3.18M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
43.9M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
43.9M
        if (ss[i] == last) {
578
            /* candidate match */
579
5.41M
            Py_ssize_t j;
580
8.56M
            for (j = 0; j < mlast; j++) {
581
5.41M
                if (s[i+j] != p[j]) {
582
2.25M
                    break;
583
2.25M
                }
584
5.41M
            }
585
5.41M
            if (j == mlast) {
586
                /* got a match! */
587
3.15M
                if (mode != FAST_COUNT) {
588
3.15M
                    return i;
589
3.15M
                }
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.25M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
46.5k
                i = i + m;
600
46.5k
            }
601
2.21M
            else {
602
2.21M
                i = i + gap;
603
2.21M
            }
604
2.25M
        }
605
38.5M
        else {
606
            /* skip: check if next character is part of pattern */
607
38.5M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
35.1M
                i = i + m;
609
35.1M
            }
610
38.5M
        }
611
43.9M
    }
612
26.4k
    return mode == FAST_COUNT ? count : -1;
613
3.18M
}
unicodeobject.c:ucs1lib_default_find
Line
Count
Source
560
20.0M
{
561
20.0M
    const Py_ssize_t w = n - m;
562
20.0M
    Py_ssize_t mlast = m - 1, count = 0;
563
20.0M
    Py_ssize_t gap = mlast;
564
20.0M
    const STRINGLIB_CHAR last = p[mlast];
565
20.0M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
20.0M
    unsigned long mask = 0;
568
109M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
89.6M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
89.6M
        if (p[i] == last) {
571
2.07M
            gap = mlast - i - 1;
572
2.07M
        }
573
89.6M
    }
574
20.0M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
321M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
303M
        if (ss[i] == last) {
578
            /* candidate match */
579
18.9M
            Py_ssize_t j;
580
26.9M
            for (j = 0; j < mlast; j++) {
581
19.1M
                if (s[i+j] != p[j]) {
582
11.2M
                    break;
583
11.2M
                }
584
19.1M
            }
585
18.9M
            if (j == mlast) {
586
                /* got a match! */
587
7.71M
                if (mode != FAST_COUNT) {
588
2.30M
                    return i;
589
2.30M
                }
590
5.41M
                count++;
591
5.41M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
5.41M
                i = i + mlast;
595
5.41M
                continue;
596
5.41M
            }
597
            /* miss: check if next character is part of pattern */
598
11.2M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.85M
                i = i + m;
600
1.85M
            }
601
9.40M
            else {
602
9.40M
                i = i + gap;
603
9.40M
            }
604
11.2M
        }
605
284M
        else {
606
            /* skip: check if next character is part of pattern */
607
284M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
225M
                i = i + m;
609
225M
            }
610
284M
        }
611
303M
    }
612
17.6M
    return mode == FAST_COUNT ? count : -1;
613
20.0M
}
unicodeobject.c:ucs2lib_default_find
Line
Count
Source
560
3.19M
{
561
3.19M
    const Py_ssize_t w = n - m;
562
3.19M
    Py_ssize_t mlast = m - 1, count = 0;
563
3.19M
    Py_ssize_t gap = mlast;
564
3.19M
    const STRINGLIB_CHAR last = p[mlast];
565
3.19M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
3.19M
    unsigned long mask = 0;
568
6.40M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.21M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.21M
        if (p[i] == last) {
571
40.5k
            gap = mlast - i - 1;
572
40.5k
        }
573
3.21M
    }
574
3.19M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
218M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
218M
        if (ss[i] == last) {
578
            /* candidate match */
579
10.6M
            Py_ssize_t j;
580
16.7M
            for (j = 0; j < mlast; j++) {
581
10.6M
                if (s[i+j] != p[j]) {
582
4.54M
                    break;
583
4.54M
                }
584
10.6M
            }
585
10.6M
            if (j == mlast) {
586
                /* got a match! */
587
6.10M
                if (mode != FAST_COUNT) {
588
3.09M
                    return i;
589
3.09M
                }
590
3.01M
                count++;
591
3.01M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
3.01M
                i = i + mlast;
595
3.01M
                continue;
596
3.01M
            }
597
            /* miss: check if next character is part of pattern */
598
4.54M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.00M
                i = i + m;
600
1.00M
            }
601
3.53M
            else {
602
3.53M
                i = i + gap;
603
3.53M
            }
604
4.54M
        }
605
207M
        else {
606
            /* skip: check if next character is part of pattern */
607
207M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
201M
                i = i + m;
609
201M
            }
610
207M
        }
611
218M
    }
612
96.3k
    return mode == FAST_COUNT ? count : -1;
613
3.19M
}
unicodeobject.c:ucs4lib_default_find
Line
Count
Source
560
5.25M
{
561
5.25M
    const Py_ssize_t w = n - m;
562
5.25M
    Py_ssize_t mlast = m - 1, count = 0;
563
5.25M
    Py_ssize_t gap = mlast;
564
5.25M
    const STRINGLIB_CHAR last = p[mlast];
565
5.25M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
5.25M
    unsigned long mask = 0;
568
10.5M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
5.25M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
5.25M
        if (p[i] == last) {
571
18.6k
            gap = mlast - i - 1;
572
18.6k
        }
573
5.25M
    }
574
5.25M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
232M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
232M
        if (ss[i] == last) {
578
            /* candidate match */
579
14.1M
            Py_ssize_t j;
580
24.5M
            for (j = 0; j < mlast; j++) {
581
14.1M
                if (s[i+j] != p[j]) {
582
3.73M
                    break;
583
3.73M
                }
584
14.1M
            }
585
14.1M
            if (j == mlast) {
586
                /* got a match! */
587
10.4M
                if (mode != FAST_COUNT) {
588
5.22M
                    return i;
589
5.22M
                }
590
5.19M
                count++;
591
5.19M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
5.19M
                i = i + mlast;
595
5.19M
                continue;
596
5.19M
            }
597
            /* miss: check if next character is part of pattern */
598
3.73M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.45M
                i = i + m;
600
1.45M
            }
601
2.27M
            else {
602
2.27M
                i = i + gap;
603
2.27M
            }
604
3.73M
        }
605
218M
        else {
606
            /* skip: check if next character is part of pattern */
607
218M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
212M
                i = i + m;
609
212M
            }
610
218M
        }
611
232M
    }
612
29.9k
    return mode == FAST_COUNT ? count : -1;
613
5.25M
}
bytes_methods.c:stringlib_default_find
Line
Count
Source
560
2.74k
{
561
2.74k
    const Py_ssize_t w = n - m;
562
2.74k
    Py_ssize_t mlast = m - 1, count = 0;
563
2.74k
    Py_ssize_t gap = mlast;
564
2.74k
    const STRINGLIB_CHAR last = p[mlast];
565
2.74k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
2.74k
    unsigned long mask = 0;
568
10.9k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
8.24k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
8.24k
        if (p[i] == last) {
571
2.74k
            gap = mlast - i - 1;
572
2.74k
        }
573
8.24k
    }
574
2.74k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
2.97M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
2.97M
        if (ss[i] == last) {
578
            /* candidate match */
579
27.8k
            Py_ssize_t j;
580
35.7k
            for (j = 0; j < mlast; j++) {
581
33.2k
                if (s[i+j] != p[j]) {
582
25.3k
                    break;
583
25.3k
                }
584
33.2k
            }
585
27.8k
            if (j == mlast) {
586
                /* got a match! */
587
2.50k
                if (mode != FAST_COUNT) {
588
2.50k
                    return i;
589
2.50k
                }
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
25.3k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
20.3k
                i = i + m;
600
20.3k
            }
601
5.00k
            else {
602
5.00k
                i = i + gap;
603
5.00k
            }
604
25.3k
        }
605
2.94M
        else {
606
            /* skip: check if next character is part of pattern */
607
2.94M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
1.15M
                i = i + m;
609
1.15M
            }
610
2.94M
        }
611
2.97M
    }
612
246
    return mode == FAST_COUNT ? count : -1;
613
2.74k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_default_find
614
615
616
static Py_ssize_t
617
STRINGLIB(adaptive_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
618
                         const STRINGLIB_CHAR* p, Py_ssize_t m,
619
                         Py_ssize_t maxcount, int mode)
620
0
{
621
0
    const Py_ssize_t w = n - m;
622
0
    Py_ssize_t mlast = m - 1, count = 0;
623
0
    Py_ssize_t gap = mlast;
624
0
    Py_ssize_t hits = 0, res;
625
0
    const STRINGLIB_CHAR last = p[mlast];
626
0
    const STRINGLIB_CHAR *const ss = &s[mlast];
627
628
0
    unsigned long mask = 0;
629
0
    for (Py_ssize_t i = 0; i < mlast; i++) {
630
0
        STRINGLIB_BLOOM_ADD(mask, p[i]);
631
0
        if (p[i] == last) {
632
0
            gap = mlast - i - 1;
633
0
        }
634
0
    }
635
0
    STRINGLIB_BLOOM_ADD(mask, last);
636
637
0
    for (Py_ssize_t i = 0; i <= w; i++) {
638
0
        if (ss[i] == last) {
639
            /* candidate match */
640
0
            Py_ssize_t j;
641
0
            for (j = 0; j < mlast; j++) {
642
0
                if (s[i+j] != p[j]) {
643
0
                    break;
644
0
                }
645
0
            }
646
0
            if (j == mlast) {
647
                /* got a match! */
648
0
                if (mode != FAST_COUNT) {
649
0
                    return i;
650
0
                }
651
0
                count++;
652
0
                if (count == maxcount) {
653
0
                    return maxcount;
654
0
                }
655
0
                i = i + mlast;
656
0
                continue;
657
0
            }
658
0
            hits += j + 1;
659
0
            if (hits > m / 4 && w - i > 2000) {
660
0
                if (mode == FAST_SEARCH) {
661
0
                    res = STRINGLIB(_two_way_find)(s + i, n - i, p, m);
662
0
                    return res == -1 ? -1 : res + i;
663
0
                }
664
0
                else {
665
0
                    res = STRINGLIB(_two_way_count)(s + i, n - i, p, m,
666
0
                                                    maxcount - count);
667
0
                    return res + count;
668
0
                }
669
0
            }
670
            /* miss: check if next character is part of pattern */
671
0
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
672
0
                i = i + m;
673
0
            }
674
0
            else {
675
0
                i = i + gap;
676
0
            }
677
0
        }
678
0
        else {
679
            /* skip: check if next character is part of pattern */
680
0
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
681
0
                i = i + m;
682
0
            }
683
0
        }
684
0
    }
685
0
    return mode == FAST_COUNT ? count : -1;
686
0
}
Unexecuted instantiation: bytesobject.c:stringlib_adaptive_find
Unexecuted instantiation: unicodeobject.c:asciilib_adaptive_find
Unexecuted instantiation: unicodeobject.c:ucs1lib_adaptive_find
Unexecuted instantiation: unicodeobject.c:ucs2lib_adaptive_find
Unexecuted instantiation: unicodeobject.c:ucs4lib_adaptive_find
Unexecuted instantiation: bytes_methods.c:stringlib_adaptive_find
Unexecuted instantiation: bytearrayobject.c:stringlib_adaptive_find
687
688
689
static Py_ssize_t
690
STRINGLIB(default_rfind)(const STRINGLIB_CHAR* s, Py_ssize_t n,
691
                         const STRINGLIB_CHAR* p, Py_ssize_t m,
692
                         Py_ssize_t maxcount, int mode)
693
7.05k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.05k
    unsigned long mask = 0;
696
7.05k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.05k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
28.2k
    for (i = mlast; i > 0; i--) {
702
21.1k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.1k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.1k
    }
707
708
1.55M
    for (i = w; i >= 0; i--) {
709
1.55M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
75.7k
            for (j = mlast; j > 0; j--) {
712
68.7k
                if (s[i+j] != p[j]) {
713
47.3k
                    break;
714
47.3k
                }
715
68.7k
            }
716
54.3k
            if (j == 0) {
717
                /* got a match! */
718
6.96k
                return i;
719
6.96k
            }
720
            /* miss: check if previous character is part of pattern */
721
47.3k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
46.1k
                i = i - m;
723
46.1k
            }
724
1.25k
            else {
725
1.25k
                i = i - skip;
726
1.25k
            }
727
47.3k
        }
728
1.49M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.49M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.26M
                i = i - m;
732
1.26M
            }
733
1.49M
        }
734
1.55M
    }
735
90
    return -1;
736
7.05k
}
Unexecuted instantiation: bytesobject.c:stringlib_default_rfind
Unexecuted instantiation: unicodeobject.c:asciilib_default_rfind
Unexecuted instantiation: unicodeobject.c:ucs1lib_default_rfind
Unexecuted instantiation: unicodeobject.c:ucs2lib_default_rfind
Unexecuted instantiation: unicodeobject.c:ucs4lib_default_rfind
bytes_methods.c:stringlib_default_rfind
Line
Count
Source
693
7.05k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.05k
    unsigned long mask = 0;
696
7.05k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.05k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
28.2k
    for (i = mlast; i > 0; i--) {
702
21.1k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.1k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.1k
    }
707
708
1.55M
    for (i = w; i >= 0; i--) {
709
1.55M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
75.7k
            for (j = mlast; j > 0; j--) {
712
68.7k
                if (s[i+j] != p[j]) {
713
47.3k
                    break;
714
47.3k
                }
715
68.7k
            }
716
54.3k
            if (j == 0) {
717
                /* got a match! */
718
6.96k
                return i;
719
6.96k
            }
720
            /* miss: check if previous character is part of pattern */
721
47.3k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
46.1k
                i = i - m;
723
46.1k
            }
724
1.25k
            else {
725
1.25k
                i = i - skip;
726
1.25k
            }
727
47.3k
        }
728
1.49M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.49M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.26M
                i = i - m;
732
1.26M
            }
733
1.49M
        }
734
1.55M
    }
735
90
    return -1;
736
7.05k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_default_rfind
737
738
739
static inline Py_ssize_t
740
STRINGLIB(count_char)(const STRINGLIB_CHAR *s, Py_ssize_t n,
741
                      const STRINGLIB_CHAR p0, Py_ssize_t maxcount)
742
0
{
743
0
    Py_ssize_t i, count = 0;
744
0
    for (i = 0; i < n; i++) {
745
0
        if (s[i] == p0) {
746
0
            count++;
747
0
            if (count == maxcount) {
748
0
                return maxcount;
749
0
            }
750
0
        }
751
0
    }
752
0
    return count;
753
0
}
Unexecuted instantiation: bytesobject.c:stringlib_count_char
Unexecuted instantiation: unicodeobject.c:asciilib_count_char
Unexecuted instantiation: unicodeobject.c:ucs1lib_count_char
Unexecuted instantiation: unicodeobject.c:ucs2lib_count_char
Unexecuted instantiation: unicodeobject.c:ucs4lib_count_char
Unexecuted instantiation: bytes_methods.c:stringlib_count_char
Unexecuted instantiation: bytearrayobject.c:stringlib_count_char
754
755
756
static inline Py_ssize_t
757
STRINGLIB(count_char_no_maxcount)(const STRINGLIB_CHAR *s, Py_ssize_t n,
758
                                  const STRINGLIB_CHAR p0)
759
/* A specialized function of count_char that does not cut off at a maximum.
760
   As a result, the compiler is able to vectorize the loop. */
761
27.9M
{
762
27.9M
    Py_ssize_t count = 0;
763
4.06G
    for (Py_ssize_t i = 0; i < n; i++) {
764
4.04G
        if (s[i] == p0) {
765
670M
            count++;
766
670M
        }
767
4.04G
    }
768
27.9M
    return count;
769
27.9M
}
Unexecuted instantiation: bytesobject.c:stringlib_count_char_no_maxcount
Unexecuted instantiation: unicodeobject.c:asciilib_count_char_no_maxcount
unicodeobject.c:ucs1lib_count_char_no_maxcount
Line
Count
Source
761
21.9M
{
762
21.9M
    Py_ssize_t count = 0;
763
609M
    for (Py_ssize_t i = 0; i < n; i++) {
764
587M
        if (s[i] == p0) {
765
31.0M
            count++;
766
31.0M
        }
767
587M
    }
768
21.9M
    return count;
769
21.9M
}
unicodeobject.c:ucs2lib_count_char_no_maxcount
Line
Count
Source
761
733k
{
762
733k
    Py_ssize_t count = 0;
763
444M
    for (Py_ssize_t i = 0; i < n; i++) {
764
444M
        if (s[i] == p0) {
765
12.5M
            count++;
766
12.5M
        }
767
444M
    }
768
733k
    return count;
769
733k
}
unicodeobject.c:ucs4lib_count_char_no_maxcount
Line
Count
Source
761
100k
{
762
100k
    Py_ssize_t count = 0;
763
355M
    for (Py_ssize_t i = 0; i < n; i++) {
764
355M
        if (s[i] == p0) {
765
11.2M
            count++;
766
11.2M
        }
767
355M
    }
768
100k
    return count;
769
100k
}
bytes_methods.c:stringlib_count_char_no_maxcount
Line
Count
Source
761
5.18M
{
762
5.18M
    Py_ssize_t count = 0;
763
2.65G
    for (Py_ssize_t i = 0; i < n; i++) {
764
2.65G
        if (s[i] == p0) {
765
615M
            count++;
766
615M
        }
767
2.65G
    }
768
5.18M
    return count;
769
5.18M
}
Unexecuted instantiation: bytearrayobject.c:stringlib_count_char_no_maxcount
770
771
772
Py_LOCAL_INLINE(Py_ssize_t)
773
FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n,
774
           const STRINGLIB_CHAR* p, Py_ssize_t m,
775
           Py_ssize_t maxcount, int mode)
776
80.6M
{
777
80.6M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
519
        return -1;
779
519
    }
780
781
    /* look for special cases */
782
80.6M
    if (m <= 1) {
783
49.0M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
49.0M
        if (mode == FAST_SEARCH)
788
21.0M
            return STRINGLIB(find_char)(s, n, p[0]);
789
27.9M
        else if (mode == FAST_RSEARCH)
790
62.0k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
27.9M
        else {
792
27.9M
            if (maxcount == PY_SSIZE_T_MAX) {
793
27.9M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
27.9M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
27.9M
        }
797
49.0M
    }
798
799
31.6M
    if (mode != FAST_RSEARCH) {
800
31.6M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
31.6M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
31.6M
        }
803
22
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
22
            if (mode == FAST_SEARCH) {
810
22
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
22
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
22
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
31.6M
    }
825
7.05k
    else {
826
        /* FAST_RSEARCH */
827
7.05k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.05k
    }
829
31.6M
}
bytesobject.c:fastsearch
Line
Count
Source
776
290k
{
777
290k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
290k
    if (m <= 1) {
783
290k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
290k
        if (mode == FAST_SEARCH)
788
290k
            return STRINGLIB(find_char)(s, n, p[0]);
789
0
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
0
        else {
792
0
            if (maxcount == PY_SSIZE_T_MAX) {
793
0
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
0
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
0
        }
797
290k
    }
798
799
0
    if (mode != FAST_RSEARCH) {
800
0
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
0
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
0
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
0
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
0
}
unicodeobject.c:asciilib_fastsearch
Line
Count
Source
776
8.12M
{
777
8.12M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
8.12M
    if (m <= 1) {
783
4.94M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
4.94M
        if (mode == FAST_SEARCH)
788
4.88M
            return STRINGLIB(find_char)(s, n, p[0]);
789
62.0k
        else if (mode == FAST_RSEARCH)
790
62.0k
            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
4.94M
    }
798
799
3.18M
    if (mode != FAST_RSEARCH) {
800
3.18M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
3.18M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
3.18M
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
3.18M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
3.18M
}
unicodeobject.c:ucs1lib_fastsearch
Line
Count
Source
776
50.4M
{
777
50.4M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
50.4M
    if (m <= 1) {
783
30.4M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
30.4M
        if (mode == FAST_SEARCH)
788
8.52M
            return STRINGLIB(find_char)(s, n, p[0]);
789
21.9M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
21.9M
        else {
792
21.9M
            if (maxcount == PY_SSIZE_T_MAX) {
793
21.9M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
21.9M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
21.9M
        }
797
30.4M
    }
798
799
20.0M
    if (mode != FAST_RSEARCH) {
800
20.0M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
20.0M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
20.0M
        }
803
22
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
22
            if (mode == FAST_SEARCH) {
810
22
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
22
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
22
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
20.0M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
20.0M
}
unicodeobject.c:ucs2lib_fastsearch
Line
Count
Source
776
7.56M
{
777
7.56M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
502
        return -1;
779
502
    }
780
781
    /* look for special cases */
782
7.56M
    if (m <= 1) {
783
4.37M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
4.37M
        if (mode == FAST_SEARCH)
788
3.63M
            return STRINGLIB(find_char)(s, n, p[0]);
789
733k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
733k
        else {
792
733k
            if (maxcount == PY_SSIZE_T_MAX) {
793
733k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
733k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
733k
        }
797
4.37M
    }
798
799
3.19M
    if (mode != FAST_RSEARCH) {
800
3.19M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
3.19M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
3.19M
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
3.19M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
3.19M
}
unicodeobject.c:ucs4lib_fastsearch
Line
Count
Source
776
9.03M
{
777
9.03M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
9.03M
    if (m <= 1) {
783
3.78M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
3.78M
        if (mode == FAST_SEARCH)
788
3.68M
            return STRINGLIB(find_char)(s, n, p[0]);
789
100k
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
100k
        else {
792
100k
            if (maxcount == PY_SSIZE_T_MAX) {
793
100k
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
100k
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
100k
        }
797
3.78M
    }
798
799
5.25M
    if (mode != FAST_RSEARCH) {
800
5.25M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
5.25M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
5.25M
        }
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.25M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
5.25M
}
bytes_methods.c:fastsearch
Line
Count
Source
776
5.19M
{
777
5.19M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
17
        return -1;
779
17
    }
780
781
    /* look for special cases */
782
5.19M
    if (m <= 1) {
783
5.18M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
5.18M
        if (mode == FAST_SEARCH)
788
0
            return STRINGLIB(find_char)(s, n, p[0]);
789
5.18M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
5.18M
        else {
792
5.18M
            if (maxcount == PY_SSIZE_T_MAX) {
793
5.18M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
5.18M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
5.18M
        }
797
5.18M
    }
798
799
9.80k
    if (mode != FAST_RSEARCH) {
800
2.74k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
2.74k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
2.74k
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
2.74k
    }
825
7.05k
    else {
826
        /* FAST_RSEARCH */
827
7.05k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.05k
    }
829
9.80k
}
Unexecuted instantiation: bytearrayobject.c:fastsearch
830