Coverage Report

Created: 2026-04-12 06:54

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
290M
#define FAST_COUNT 0
25
118M
#define FAST_SEARCH 1
26
76.8M
#define FAST_RSEARCH 2
27
28
#if LONG_BIT >= 128
29
#define STRINGLIB_BLOOM_WIDTH 128
30
#elif LONG_BIT >= 64
31
1.20G
#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
208M
    ((mask |= (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
40
#define STRINGLIB_BLOOM(mask, ch)     \
41
1.00G
    ((mask &  (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
42
43
#ifdef STRINGLIB_FAST_MEMCHR
44
248M
#  define MEMCHR_CUT_OFF 15
45
#else
46
8.76M
#  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
256M
{
52
256M
    const STRINGLIB_CHAR *p, *e;
53
54
256M
    p = s;
55
256M
    e = s + n;
56
256M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
37.9M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
37.9M
        if (p != NULL)
60
36.1M
            return (p - s);
61
1.79M
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
        const STRINGLIB_CHAR *s1, *e1;
66
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
8.22M
        if (needle != 0) {
71
8.23M
            do {
72
8.23M
                const void *candidate = memchr(p, needle,
73
8.23M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
8.23M
                if (candidate == NULL)
75
64.2k
                    return -1;
76
8.17M
                s1 = p;
77
8.17M
                p = (const STRINGLIB_CHAR *)
78
8.17M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
8.17M
                if (*p == ch)
80
8.14M
                    return (p - s);
81
                /* False positive */
82
31.6k
                p++;
83
31.6k
                if (p - s1 > MEMCHR_CUT_OFF)
84
12.4k
                    continue;
85
19.2k
                if (e - p <= MEMCHR_CUT_OFF)
86
1.90k
                    break;
87
17.2k
                e1 = p + MEMCHR_CUT_OFF;
88
582k
                while (p != e1) {
89
569k
                    if (*p == ch)
90
3.88k
                        return (p - s);
91
565k
                    p++;
92
565k
                }
93
17.2k
            }
94
8.21M
            while (e - p > MEMCHR_CUT_OFF);
95
8.21M
        }
96
#endif
97
46.1M
    }
98
1.14G
    while (p < e) {
99
953M
        if (*p == ch)
100
21.9M
            return (p - s);
101
931M
        p++;
102
931M
    }
103
188M
    return -1;
104
210M
}
bytesobject.c:stringlib_find_char
Line
Count
Source
51
515k
{
52
515k
    const STRINGLIB_CHAR *p, *e;
53
54
515k
    p = s;
55
515k
    e = s + n;
56
515k
    if (n > MEMCHR_CUT_OFF) {
57
515k
#ifdef STRINGLIB_FAST_MEMCHR
58
515k
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
515k
        if (p != NULL)
60
510k
            return (p - s);
61
4.75k
        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
515k
    }
98
84
    while (p < e) {
99
84
        if (*p == ch)
100
14
            return (p - s);
101
70
        p++;
102
70
    }
103
0
    return -1;
104
14
}
unicodeobject.c:ucs1lib_find_char
Line
Count
Source
51
217M
{
52
217M
    const STRINGLIB_CHAR *p, *e;
53
54
217M
    p = s;
55
217M
    e = s + n;
56
217M
    if (n > MEMCHR_CUT_OFF) {
57
20.2M
#ifdef STRINGLIB_FAST_MEMCHR
58
20.2M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
20.2M
        if (p != NULL)
60
19.1M
            return (p - s);
61
1.12M
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
        const STRINGLIB_CHAR *s1, *e1;
66
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
        if (needle != 0) {
71
            do {
72
                const void *candidate = memchr(p, needle,
73
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
                if (candidate == NULL)
75
                    return -1;
76
                s1 = p;
77
                p = (const STRINGLIB_CHAR *)
78
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
                if (*p == ch)
80
                    return (p - s);
81
                /* False positive */
82
                p++;
83
                if (p - s1 > MEMCHR_CUT_OFF)
84
                    continue;
85
                if (e - p <= MEMCHR_CUT_OFF)
86
                    break;
87
                e1 = p + MEMCHR_CUT_OFF;
88
                while (p != e1) {
89
                    if (*p == ch)
90
                        return (p - s);
91
                    p++;
92
                }
93
            }
94
            while (e - p > MEMCHR_CUT_OFF);
95
        }
96
#endif
97
20.2M
    }
98
1.03G
    while (p < e) {
99
850M
        if (*p == ch)
100
12.8M
            return (p - s);
101
838M
        p++;
102
838M
    }
103
184M
    return -1;
104
196M
}
unicodeobject.c:ucs2lib_find_char
Line
Count
Source
51
8.66M
{
52
8.66M
    const STRINGLIB_CHAR *p, *e;
53
54
8.66M
    p = s;
55
8.66M
    e = s + n;
56
8.66M
    if (n > MEMCHR_CUT_OFF) {
57
#ifdef STRINGLIB_FAST_MEMCHR
58
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
        if (p != NULL)
60
            return (p - s);
61
        return -1;
62
#else
63
        /* use memchr if we can choose a needle without too many likely
64
           false positives */
65
8.22M
        const STRINGLIB_CHAR *s1, *e1;
66
8.22M
        unsigned char needle = ch & 0xff;
67
        /* If looking for a multiple of 256, we'd have too
68
           many false positives looking for the '\0' byte in UCS2
69
           and UCS4 representations. */
70
8.22M
        if (needle != 0) {
71
8.23M
            do {
72
8.23M
                const void *candidate = memchr(p, needle,
73
8.23M
                                               (e - p) * sizeof(STRINGLIB_CHAR));
74
8.23M
                if (candidate == NULL)
75
64.2k
                    return -1;
76
8.17M
                s1 = p;
77
8.17M
                p = (const STRINGLIB_CHAR *)
78
8.17M
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
79
8.17M
                if (*p == ch)
80
8.14M
                    return (p - s);
81
                /* False positive */
82
31.6k
                p++;
83
31.6k
                if (p - s1 > MEMCHR_CUT_OFF)
84
12.4k
                    continue;
85
19.2k
                if (e - p <= MEMCHR_CUT_OFF)
86
1.90k
                    break;
87
17.2k
                e1 = p + MEMCHR_CUT_OFF;
88
582k
                while (p != e1) {
89
569k
                    if (*p == ch)
90
3.88k
                        return (p - s);
91
565k
                    p++;
92
565k
                }
93
17.2k
            }
94
8.21M
            while (e - p > MEMCHR_CUT_OFF);
95
8.21M
        }
96
8.22M
#endif
97
8.22M
    }
98
6.96M
    while (p < e) {
99
6.72M
        if (*p == ch)
100
224k
            return (p - s);
101
6.50M
        p++;
102
6.50M
    }
103
234k
    return -1;
104
458k
}
unicodeobject.c:ucs4lib_find_char
Line
Count
Source
51
6.98M
{
52
6.98M
    const STRINGLIB_CHAR *p, *e;
53
54
6.98M
    p = s;
55
6.98M
    e = s + n;
56
6.98M
    if (n > MEMCHR_CUT_OFF) {
57
6.92M
#ifdef STRINGLIB_FAST_MEMCHR
58
6.92M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
6.92M
        if (p != NULL)
60
6.91M
            return (p - s);
61
15.4k
        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
6.92M
    }
98
214k
    while (p < e) {
99
183k
        if (*p == ch)
100
22.8k
            return (p - s);
101
160k
        p++;
102
160k
    }
103
31.6k
    return -1;
104
54.4k
}
unicodeobject.c:asciilib_find_char
Line
Count
Source
51
5.75M
{
52
5.75M
    const STRINGLIB_CHAR *p, *e;
53
54
5.75M
    p = s;
55
5.75M
    e = s + n;
56
5.75M
    if (n > MEMCHR_CUT_OFF) {
57
4.50M
#ifdef STRINGLIB_FAST_MEMCHR
58
4.50M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
4.50M
        if (p != NULL)
60
4.00M
            return (p - s);
61
493k
        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.50M
    }
98
3.93M
    while (p < e) {
99
3.87M
        if (*p == ch)
100
1.19M
            return (p - s);
101
2.68M
        p++;
102
2.68M
    }
103
56.9k
    return -1;
104
1.25M
}
bytes_methods.c:stringlib_find_char
Line
Count
Source
51
17.8M
{
52
17.8M
    const STRINGLIB_CHAR *p, *e;
53
54
17.8M
    p = s;
55
17.8M
    e = s + n;
56
17.8M
    if (n > MEMCHR_CUT_OFF) {
57
5.76M
#ifdef STRINGLIB_FAST_MEMCHR
58
5.76M
        p = STRINGLIB_FAST_MEMCHR(s, ch, n);
59
5.76M
        if (p != NULL)
60
5.61M
            return (p - s);
61
154k
        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
5.76M
    }
98
95.9M
    while (p < e) {
99
91.5M
        if (*p == ch)
100
7.72M
            return (p - s);
101
83.8M
        p++;
102
83.8M
    }
103
4.32M
    return -1;
104
12.0M
}
Unexecuted instantiation: bytearrayobject.c:stringlib_find_char
105
106
#undef MEMCHR_CUT_OFF
107
108
#if STRINGLIB_SIZEOF_CHAR == 1
109
125k
#  define MEMRCHR_CUT_OFF 15
110
#else
111
424k
#  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
516k
{
118
516k
    const STRINGLIB_CHAR *p;
119
516k
#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
516k
    if (n > MEMRCHR_CUT_OFF) {
126
#if STRINGLIB_SIZEOF_CHAR == 1
127
        p = memrchr(s, ch, n);
128
82.1k
        if (p != NULL)
129
79.1k
            return (p - s);
130
3.01k
        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
350k
        if (needle != 0) {
141
359k
            do {
142
359k
                void *candidate = memrchr(s, needle,
143
359k
                                          n * sizeof(STRINGLIB_CHAR));
144
359k
                if (candidate == NULL)
145
1.56k
                    return -1;
146
358k
                n1 = n;
147
358k
                p = (const STRINGLIB_CHAR *)
148
358k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
358k
                n = p - s;
150
358k
                if (*p == ch)
151
346k
                    return n;
152
                /* False positive */
153
11.9k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
5.41k
                    continue;
155
6.52k
                if (n <= MEMRCHR_CUT_OFF)
156
1.31k
                    break;
157
5.21k
                s1 = p - MEMRCHR_CUT_OFF;
158
198k
                while (p > s1) {
159
193k
                    p--;
160
193k
                    if (*p == ch)
161
616
                        return (p - s);
162
193k
                }
163
4.59k
                n = p - s;
164
4.59k
            }
165
350k
            while (n > MEMRCHR_CUT_OFF);
166
350k
        }
167
#endif
168
432k
    }
169
86.0k
#endif  /* HAVE_MEMRCHR */
170
86.0k
    p = s + n;
171
484k
    while (p > s) {
172
452k
        p--;
173
452k
        if (*p == ch)
174
54.1k
            return (p - s);
175
452k
    }
176
31.9k
    return -1;
177
86.0k
}
Unexecuted instantiation: bytesobject.c:stringlib_rfind_char
unicodeobject.c:ucs1lib_rfind_char
Line
Count
Source
117
68.2k
{
118
68.2k
    const STRINGLIB_CHAR *p;
119
68.2k
#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
68.2k
    if (n > MEMRCHR_CUT_OFF) {
126
63.4k
#if STRINGLIB_SIZEOF_CHAR == 1
127
63.4k
        p = memrchr(s, ch, n);
128
63.4k
        if (p != NULL)
129
61.4k
            return (p - s);
130
2.00k
        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
63.4k
    }
169
4.78k
#endif  /* HAVE_MEMRCHR */
170
4.78k
    p = s + n;
171
19.2k
    while (p > s) {
172
17.6k
        p--;
173
17.6k
        if (*p == ch)
174
3.16k
            return (p - s);
175
17.6k
    }
176
1.61k
    return -1;
177
4.78k
}
unicodeobject.c:ucs2lib_rfind_char
Line
Count
Source
117
292k
{
118
292k
    const STRINGLIB_CHAR *p;
119
292k
#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
292k
    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
279k
        const STRINGLIB_CHAR *s1;
135
279k
        Py_ssize_t n1;
136
279k
        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
279k
        if (needle != 0) {
141
282k
            do {
142
282k
                void *candidate = memrchr(s, needle,
143
282k
                                          n * sizeof(STRINGLIB_CHAR));
144
282k
                if (candidate == NULL)
145
882
                    return -1;
146
281k
                n1 = n;
147
281k
                p = (const STRINGLIB_CHAR *)
148
281k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
281k
                n = p - s;
150
281k
                if (*p == ch)
151
276k
                    return n;
152
                /* False positive */
153
4.50k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
1.86k
                    continue;
155
2.63k
                if (n <= MEMRCHR_CUT_OFF)
156
932
                    break;
157
1.70k
                s1 = p - MEMRCHR_CUT_OFF;
158
63.6k
                while (p > s1) {
159
62.2k
                    p--;
160
62.2k
                    if (*p == ch)
161
255
                        return (p - s);
162
62.2k
                }
163
1.45k
                n = p - s;
164
1.45k
            }
165
279k
            while (n > MEMRCHR_CUT_OFF);
166
279k
        }
167
279k
#endif
168
279k
    }
169
14.4k
#endif  /* HAVE_MEMRCHR */
170
14.4k
    p = s + n;
171
66.8k
    while (p > s) {
172
64.5k
        p--;
173
64.5k
        if (*p == ch)
174
12.0k
            return (p - s);
175
64.5k
    }
176
2.33k
    return -1;
177
14.4k
}
unicodeobject.c:ucs4lib_rfind_char
Line
Count
Source
117
98.9k
{
118
98.9k
    const STRINGLIB_CHAR *p;
119
98.9k
#ifdef HAVE_MEMRCHR
120
    /* memrchr() is a GNU extension, available since glibc 2.1.91.  it
121
       doesn't seem as optimized as memchr(), but is still quite
122
       faster than our hand-written loop below. There is no wmemrchr
123
       for 4-byte chars. */
124
125
98.9k
    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
71.2k
        const STRINGLIB_CHAR *s1;
135
71.2k
        Py_ssize_t n1;
136
71.2k
        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
71.2k
        if (needle != 0) {
141
77.6k
            do {
142
77.6k
                void *candidate = memrchr(s, needle,
143
77.6k
                                          n * sizeof(STRINGLIB_CHAR));
144
77.6k
                if (candidate == NULL)
145
683
                    return -1;
146
76.9k
                n1 = n;
147
76.9k
                p = (const STRINGLIB_CHAR *)
148
76.9k
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
76.9k
                n = p - s;
150
76.9k
                if (*p == ch)
151
69.5k
                    return n;
152
                /* False positive */
153
7.43k
                if (n1 - n > MEMRCHR_CUT_OFF)
154
3.54k
                    continue;
155
3.88k
                if (n <= MEMRCHR_CUT_OFF)
156
379
                    break;
157
3.50k
                s1 = p - MEMRCHR_CUT_OFF;
158
134k
                while (p > s1) {
159
131k
                    p--;
160
131k
                    if (*p == ch)
161
361
                        return (p - s);
162
131k
                }
163
3.14k
                n = p - s;
164
3.14k
            }
165
71.2k
            while (n > MEMRCHR_CUT_OFF);
166
71.2k
        }
167
71.2k
#endif
168
71.2k
    }
169
28.3k
#endif  /* HAVE_MEMRCHR */
170
28.3k
    p = s + n;
171
176k
    while (p > s) {
172
174k
        p--;
173
174k
        if (*p == ch)
174
26.5k
            return (p - s);
175
174k
    }
176
1.79k
    return -1;
177
28.3k
}
unicodeobject.c:asciilib_rfind_char
Line
Count
Source
117
50.2k
{
118
50.2k
    const STRINGLIB_CHAR *p;
119
50.2k
#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
50.2k
    if (n > MEMRCHR_CUT_OFF) {
126
17.6k
#if STRINGLIB_SIZEOF_CHAR == 1
127
17.6k
        p = memrchr(s, ch, n);
128
17.6k
        if (p != NULL)
129
17.3k
            return (p - s);
130
286
        return -1;
131
#else
132
        /* use memrchr if we can choose a needle without too many likely
133
           false positives */
134
        const STRINGLIB_CHAR *s1;
135
        Py_ssize_t n1;
136
        unsigned char needle = ch & 0xff;
137
        /* If looking for a multiple of 256, we'd have too
138
           many false positives looking for the '\0' byte in UCS2
139
           and UCS4 representations. */
140
        if (needle != 0) {
141
            do {
142
                void *candidate = memrchr(s, needle,
143
                                          n * sizeof(STRINGLIB_CHAR));
144
                if (candidate == NULL)
145
                    return -1;
146
                n1 = n;
147
                p = (const STRINGLIB_CHAR *)
148
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
                n = p - s;
150
                if (*p == ch)
151
                    return n;
152
                /* False positive */
153
                if (n1 - n > MEMRCHR_CUT_OFF)
154
                    continue;
155
                if (n <= MEMRCHR_CUT_OFF)
156
                    break;
157
                s1 = p - MEMRCHR_CUT_OFF;
158
                while (p > s1) {
159
                    p--;
160
                    if (*p == ch)
161
                        return (p - s);
162
                }
163
                n = p - s;
164
            }
165
            while (n > MEMRCHR_CUT_OFF);
166
        }
167
#endif
168
17.6k
    }
169
32.5k
#endif  /* HAVE_MEMRCHR */
170
32.5k
    p = s + n;
171
187k
    while (p > s) {
172
165k
        p--;
173
165k
        if (*p == ch)
174
10.4k
            return (p - s);
175
165k
    }
176
22.1k
    return -1;
177
32.5k
}
bytes_methods.c:stringlib_rfind_char
Line
Count
Source
117
6.98k
{
118
6.98k
    const STRINGLIB_CHAR *p;
119
6.98k
#ifdef HAVE_MEMRCHR
120
    /* memrchr() is a GNU extension, available since glibc 2.1.91.  it
121
       doesn't seem as optimized as memchr(), but is still quite
122
       faster than our hand-written loop below. There is no wmemrchr
123
       for 4-byte chars. */
124
125
6.98k
    if (n > MEMRCHR_CUT_OFF) {
126
1.04k
#if STRINGLIB_SIZEOF_CHAR == 1
127
1.04k
        p = memrchr(s, ch, n);
128
1.04k
        if (p != NULL)
129
315
            return (p - s);
130
727
        return -1;
131
#else
132
        /* use memrchr if we can choose a needle without too many likely
133
           false positives */
134
        const STRINGLIB_CHAR *s1;
135
        Py_ssize_t n1;
136
        unsigned char needle = ch & 0xff;
137
        /* If looking for a multiple of 256, we'd have too
138
           many false positives looking for the '\0' byte in UCS2
139
           and UCS4 representations. */
140
        if (needle != 0) {
141
            do {
142
                void *candidate = memrchr(s, needle,
143
                                          n * sizeof(STRINGLIB_CHAR));
144
                if (candidate == NULL)
145
                    return -1;
146
                n1 = n;
147
                p = (const STRINGLIB_CHAR *)
148
                        _Py_ALIGN_DOWN(candidate, sizeof(STRINGLIB_CHAR));
149
                n = p - s;
150
                if (*p == ch)
151
                    return n;
152
                /* False positive */
153
                if (n1 - n > MEMRCHR_CUT_OFF)
154
                    continue;
155
                if (n <= MEMRCHR_CUT_OFF)
156
                    break;
157
                s1 = p - MEMRCHR_CUT_OFF;
158
                while (p > s1) {
159
                    p--;
160
                    if (*p == ch)
161
                        return (p - s);
162
                }
163
                n = p - s;
164
            }
165
            while (n > MEMRCHR_CUT_OFF);
166
        }
167
#endif
168
1.04k
    }
169
5.94k
#endif  /* HAVE_MEMRCHR */
170
5.94k
    p = s + n;
171
34.6k
    while (p > s) {
172
30.6k
        p--;
173
30.6k
        if (*p == ch)
174
1.89k
            return (p - s);
175
30.6k
    }
176
4.05k
    return -1;
177
5.94k
}
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.0k
#define TABLE_SIZE_BITS 6u
312
79.0k
#define TABLE_SIZE (1U << TABLE_SIZE_BITS)
313
77.6k
#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
14.0k
      windowloop:
457
14.0k
        while (window_last < haystack_end) {
458
77.2k
            for (;;) {
459
77.2k
                LOG_LINEUP();
460
77.2k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
77.2k
                window_last += shift;
462
77.2k
                if (shift == 0) {
463
14.0k
                    break;
464
14.0k
                }
465
63.2k
                if (window_last >= haystack_end) {
466
18
                    return -1;
467
18
                }
468
63.1k
                LOG("Horspool skip\n");
469
63.1k
            }
470
14.0k
            window = window_last - len_needle + 1;
471
14.0k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
14.0k
                   (needle[len_needle - 1] & TABLE_MASK));
473
14.0k
            Py_ssize_t i = cut;
474
14.2k
            for (; i < len_needle; i++) {
475
14.1k
                if (needle[i] != window[i]) {
476
13.9k
                    if (i < gap_jump_end) {
477
13.9k
                        LOG("Early right half mismatch: jump by gap.\n");
478
13.9k
                        assert(gap >= i - cut + 1);
479
13.9k
                        window_last += gap;
480
13.9k
                    }
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
13.9k
                    goto windowloop;
487
13.9k
                }
488
14.1k
            }
489
199
            for (Py_ssize_t i = 0; i < cut; i++) {
490
197
                if (needle[i] != window[i]) {
491
101
                    LOG("Left half does not match.\n");
492
101
                    window_last += period;
493
101
                    goto windowloop;
494
101
                }
495
197
            }
496
2
            LOG("Found a match!\n");
497
2
            return window - haystack;
498
103
        }
499
14.0k
    }
500
2
    LOG("Not found. Returning -1.\n");
501
2
    return -1;
502
22
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way
Unexecuted instantiation: unicodeobject.c:asciilib__two_way
unicodeobject.c:ucs1lib__two_way
Line
Count
Source
372
22
{
373
    // Crochemore and Perrin's (1991) Two-Way algorithm.
374
    // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260
375
22
    const Py_ssize_t len_needle = p->len_needle;
376
22
    const Py_ssize_t cut = p->cut;
377
22
    Py_ssize_t period = p->period;
378
22
    const STRINGLIB_CHAR *const needle = p->needle;
379
22
    const STRINGLIB_CHAR *window_last = haystack + len_needle - 1;
380
22
    const STRINGLIB_CHAR *const haystack_end = haystack + len_haystack;
381
22
    SHIFT_TYPE *table = p->table;
382
22
    const STRINGLIB_CHAR *window;
383
22
    LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack);
384
385
22
    Py_ssize_t gap = p->gap;
386
22
    Py_ssize_t gap_jump_end = Py_MIN(len_needle, cut + gap);
387
22
    if (p->is_periodic) {
388
0
        LOG("Needle is periodic.\n");
389
0
        Py_ssize_t memory = 0;
390
0
      periodicwindowloop:
391
0
        while (window_last < haystack_end) {
392
0
            assert(memory == 0);
393
0
            for (;;) {
394
0
                LOG_LINEUP();
395
0
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
396
0
                window_last += shift;
397
0
                if (shift == 0) {
398
0
                    break;
399
0
                }
400
0
                if (window_last >= haystack_end) {
401
0
                    return -1;
402
0
                }
403
0
                LOG("Horspool skip\n");
404
0
            }
405
0
          no_shift:
406
0
            window = window_last - len_needle + 1;
407
0
            assert((window[len_needle - 1] & TABLE_MASK) ==
408
0
                   (needle[len_needle - 1] & TABLE_MASK));
409
0
            Py_ssize_t i = Py_MAX(cut, memory);
410
0
            for (; i < len_needle; i++) {
411
0
                if (needle[i] != window[i]) {
412
0
                    if (i < gap_jump_end) {
413
0
                        LOG("Early right half mismatch: jump by gap.\n");
414
0
                        assert(gap >= i - cut + 1);
415
0
                        window_last += gap;
416
0
                    }
417
0
                    else {
418
0
                        LOG("Late right half mismatch: jump by n (>gap)\n");
419
0
                        assert(i - cut + 1 > gap);
420
0
                        window_last += i - cut + 1;
421
0
                    }
422
0
                    memory = 0;
423
0
                    goto periodicwindowloop;
424
0
                }
425
0
            }
426
0
            for (i = memory; i < cut; i++) {
427
0
                if (needle[i] != window[i]) {
428
0
                    LOG("Left half does not match.\n");
429
0
                    window_last += period;
430
0
                    memory = len_needle - period;
431
0
                    if (window_last >= haystack_end) {
432
0
                        return -1;
433
0
                    }
434
0
                    Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
435
0
                    if (shift) {
436
                        // A mismatch has been identified to the right
437
                        // of where i will next start, so we can jump
438
                        // at least as far as if the mismatch occurred
439
                        // on the first comparison.
440
0
                        Py_ssize_t mem_jump = Py_MAX(cut, memory) - cut + 1;
441
0
                        LOG("Skip with Memory.\n");
442
0
                        memory = 0;
443
0
                        window_last += Py_MAX(shift, mem_jump);
444
0
                        goto periodicwindowloop;
445
0
                    }
446
0
                    goto no_shift;
447
0
                }
448
0
            }
449
0
            LOG("Found a match!\n");
450
0
            return window - haystack;
451
0
        }
452
0
    }
453
22
    else {
454
22
        period = Py_MAX(gap, period);
455
22
        LOG("Needle is not periodic.\n");
456
14.0k
      windowloop:
457
14.0k
        while (window_last < haystack_end) {
458
77.2k
            for (;;) {
459
77.2k
                LOG_LINEUP();
460
77.2k
                Py_ssize_t shift = table[(*window_last) & TABLE_MASK];
461
77.2k
                window_last += shift;
462
77.2k
                if (shift == 0) {
463
14.0k
                    break;
464
14.0k
                }
465
63.2k
                if (window_last >= haystack_end) {
466
18
                    return -1;
467
18
                }
468
63.1k
                LOG("Horspool skip\n");
469
63.1k
            }
470
14.0k
            window = window_last - len_needle + 1;
471
14.0k
            assert((window[len_needle - 1] & TABLE_MASK) ==
472
14.0k
                   (needle[len_needle - 1] & TABLE_MASK));
473
14.0k
            Py_ssize_t i = cut;
474
14.2k
            for (; i < len_needle; i++) {
475
14.1k
                if (needle[i] != window[i]) {
476
13.9k
                    if (i < gap_jump_end) {
477
13.9k
                        LOG("Early right half mismatch: jump by gap.\n");
478
13.9k
                        assert(gap >= i - cut + 1);
479
13.9k
                        window_last += gap;
480
13.9k
                    }
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
13.9k
                    goto windowloop;
487
13.9k
                }
488
14.1k
            }
489
199
            for (Py_ssize_t i = 0; i < cut; i++) {
490
197
                if (needle[i] != window[i]) {
491
101
                    LOG("Left half does not match.\n");
492
101
                    window_last += period;
493
101
                    goto windowloop;
494
101
                }
495
197
            }
496
2
            LOG("Found a match!\n");
497
2
            return window - haystack;
498
103
        }
499
14.0k
    }
500
2
    LOG("Not found. Returning -1.\n");
501
2
    return -1;
502
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way
Unexecuted instantiation: bytes_methods.c:stringlib__two_way
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way
503
504
505
static Py_ssize_t
506
STRINGLIB(_two_way_find)(const STRINGLIB_CHAR *haystack,
507
                         Py_ssize_t len_haystack,
508
                         const STRINGLIB_CHAR *needle,
509
                         Py_ssize_t len_needle)
510
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way_find
Unexecuted instantiation: unicodeobject.c:asciilib__two_way_find
unicodeobject.c:ucs1lib__two_way_find
Line
Count
Source
510
22
{
511
22
    LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack);
512
22
    STRINGLIB(prework) p;
513
22
    STRINGLIB(_preprocess)(needle, len_needle, &p);
514
22
    return STRINGLIB(_two_way)(haystack, len_haystack, &p);
515
22
}
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_find
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_find
Unexecuted instantiation: bytes_methods.c:stringlib__two_way_find
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_find
516
517
518
static Py_ssize_t
519
STRINGLIB(_two_way_count)(const STRINGLIB_CHAR *haystack,
520
                          Py_ssize_t len_haystack,
521
                          const STRINGLIB_CHAR *needle,
522
                          Py_ssize_t len_needle,
523
                          Py_ssize_t maxcount)
524
0
{
525
0
    LOG("###### Counting \"%s\" in \"%s\".\n", needle, haystack);
526
0
    STRINGLIB(prework) p;
527
0
    STRINGLIB(_preprocess)(needle, len_needle, &p);
528
0
    Py_ssize_t index = 0, count = 0;
529
0
    while (1) {
530
0
        Py_ssize_t result;
531
0
        result = STRINGLIB(_two_way)(haystack + index,
532
0
                                     len_haystack - index, &p);
533
0
        if (result == -1) {
534
0
            return count;
535
0
        }
536
0
        count++;
537
0
        if (count == maxcount) {
538
0
            return maxcount;
539
0
        }
540
0
        index += result + len_needle;
541
0
    }
542
0
    return count;
543
0
}
Unexecuted instantiation: bytesobject.c:stringlib__two_way_count
Unexecuted instantiation: unicodeobject.c:asciilib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs1lib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs2lib__two_way_count
Unexecuted instantiation: unicodeobject.c:ucs4lib__two_way_count
Unexecuted instantiation: bytes_methods.c:stringlib__two_way_count
Unexecuted instantiation: bytearrayobject.c:stringlib__two_way_count
544
545
#undef SHIFT_TYPE
546
#undef NOT_FOUND
547
#undef SHIFT_OVERFLOW
548
#undef TABLE_SIZE_BITS
549
#undef TABLE_SIZE
550
#undef TABLE_MASK
551
552
#undef LOG
553
#undef LOG_STRING
554
#undef LOG_LINEUP
555
556
static inline Py_ssize_t
557
STRINGLIB(default_find)(const STRINGLIB_CHAR* s, Py_ssize_t n,
558
                        const STRINGLIB_CHAR* p, Py_ssize_t m,
559
                        Py_ssize_t maxcount, int mode)
560
37.1M
{
561
37.1M
    const Py_ssize_t w = n - m;
562
37.1M
    Py_ssize_t mlast = m - 1, count = 0;
563
37.1M
    Py_ssize_t gap = mlast;
564
37.1M
    const STRINGLIB_CHAR last = p[mlast];
565
37.1M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
37.1M
    unsigned long mask = 0;
568
208M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
171M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
171M
        if (p[i] == last) {
571
1.08M
            gap = mlast - i - 1;
572
1.08M
        }
573
171M
    }
574
37.1M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
1.04G
    for (Py_ssize_t i = 0; i <= w; i++) {
577
1.02G
        if (ss[i] == last) {
578
            /* candidate match */
579
42.5M
            Py_ssize_t j;
580
66.9M
            for (j = 0; j < mlast; j++) {
581
43.9M
                if (s[i+j] != p[j]) {
582
19.5M
                    break;
583
19.5M
                }
584
43.9M
            }
585
42.5M
            if (j == mlast) {
586
                /* got a match! */
587
22.9M
                if (mode != FAST_COUNT) {
588
12.1M
                    return i;
589
12.1M
                }
590
10.8M
                count++;
591
10.8M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
10.8M
                i = i + mlast;
595
10.8M
                continue;
596
10.8M
            }
597
            /* miss: check if next character is part of pattern */
598
19.5M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
4.85M
                i = i + m;
600
4.85M
            }
601
14.6M
            else {
602
14.6M
                i = i + gap;
603
14.6M
            }
604
19.5M
        }
605
982M
        else {
606
            /* skip: check if next character is part of pattern */
607
982M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
862M
                i = i + m;
609
862M
            }
610
982M
        }
611
1.02G
    }
612
25.0M
    return mode == FAST_COUNT ? count : -1;
613
37.1M
}
Unexecuted instantiation: bytesobject.c:stringlib_default_find
unicodeobject.c:asciilib_default_find
Line
Count
Source
560
2.38M
{
561
2.38M
    const Py_ssize_t w = n - m;
562
2.38M
    Py_ssize_t mlast = m - 1, count = 0;
563
2.38M
    Py_ssize_t gap = mlast;
564
2.38M
    const STRINGLIB_CHAR last = p[mlast];
565
2.38M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
2.38M
    unsigned long mask = 0;
568
5.21M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
2.83M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
2.83M
        if (p[i] == last) {
571
20.6k
            gap = mlast - i - 1;
572
20.6k
        }
573
2.83M
    }
574
2.38M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
43.5M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
43.5M
        if (ss[i] == last) {
578
            /* candidate match */
579
4.11M
            Py_ssize_t j;
580
6.88M
            for (j = 0; j < mlast; j++) {
581
4.54M
                if (s[i+j] != p[j]) {
582
1.77M
                    break;
583
1.77M
                }
584
4.54M
            }
585
4.11M
            if (j == mlast) {
586
                /* got a match! */
587
2.33M
                if (mode != FAST_COUNT) {
588
2.33M
                    return i;
589
2.33M
                }
590
0
                count++;
591
0
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
0
                i = i + mlast;
595
0
                continue;
596
0
            }
597
            /* miss: check if next character is part of pattern */
598
1.77M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
107k
                i = i + m;
600
107k
            }
601
1.66M
            else {
602
1.66M
                i = i + gap;
603
1.66M
            }
604
1.77M
        }
605
39.4M
        else {
606
            /* skip: check if next character is part of pattern */
607
39.4M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
36.0M
                i = i + m;
609
36.0M
            }
610
39.4M
        }
611
43.5M
    }
612
43.0k
    return mode == FAST_COUNT ? count : -1;
613
2.38M
}
unicodeobject.c:ucs1lib_default_find
Line
Count
Source
560
26.9M
{
561
26.9M
    const Py_ssize_t w = n - m;
562
26.9M
    Py_ssize_t mlast = m - 1, count = 0;
563
26.9M
    Py_ssize_t gap = mlast;
564
26.9M
    const STRINGLIB_CHAR last = p[mlast];
565
26.9M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
26.9M
    unsigned long mask = 0;
568
187M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
160M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
160M
        if (p[i] == last) {
571
1.00M
            gap = mlast - i - 1;
572
1.00M
        }
573
160M
    }
574
26.9M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
440M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
415M
        if (ss[i] == last) {
578
            /* candidate match */
579
14.2M
            Py_ssize_t j;
580
20.6M
            for (j = 0; j < mlast; j++) {
581
14.8M
                if (s[i+j] != p[j]) {
582
8.50M
                    break;
583
8.50M
                }
584
14.8M
            }
585
14.2M
            if (j == mlast) {
586
                /* got a match! */
587
5.77M
                if (mode != FAST_COUNT) {
588
2.11M
                    return i;
589
2.11M
                }
590
3.65M
                count++;
591
3.65M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
3.65M
                i = i + mlast;
595
3.65M
                continue;
596
3.65M
            }
597
            /* miss: check if next character is part of pattern */
598
8.50M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
2.06M
                i = i + m;
600
2.06M
            }
601
6.43M
            else {
602
6.43M
                i = i + gap;
603
6.43M
            }
604
8.50M
        }
605
401M
        else {
606
            /* skip: check if next character is part of pattern */
607
401M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
298M
                i = i + m;
609
298M
            }
610
401M
        }
611
415M
    }
612
24.8M
    return mode == FAST_COUNT ? count : -1;
613
26.9M
}
unicodeobject.c:ucs2lib_default_find
Line
Count
Source
560
3.52M
{
561
3.52M
    const Py_ssize_t w = n - m;
562
3.52M
    Py_ssize_t mlast = m - 1, count = 0;
563
3.52M
    Py_ssize_t gap = mlast;
564
3.52M
    const STRINGLIB_CHAR last = p[mlast];
565
3.52M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
3.52M
    unsigned long mask = 0;
568
7.33M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.80M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.80M
        if (p[i] == last) {
571
38.1k
            gap = mlast - i - 1;
572
38.1k
        }
573
3.80M
    }
574
3.52M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
352M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
352M
        if (ss[i] == last) {
578
            /* candidate match */
579
10.9M
            Py_ssize_t j;
580
17.7M
            for (j = 0; j < mlast; j++) {
581
11.2M
                if (s[i+j] != p[j]) {
582
4.39M
                    break;
583
4.39M
                }
584
11.2M
            }
585
10.9M
            if (j == mlast) {
586
                /* got a match! */
587
6.51M
                if (mode != FAST_COUNT) {
588
3.42M
                    return i;
589
3.42M
                }
590
3.09M
                count++;
591
3.09M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
3.09M
                i = i + mlast;
595
3.09M
                continue;
596
3.09M
            }
597
            /* miss: check if next character is part of pattern */
598
4.39M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.07M
                i = i + m;
600
1.07M
            }
601
3.32M
            else {
602
3.32M
                i = i + gap;
603
3.32M
            }
604
4.39M
        }
605
341M
        else {
606
            /* skip: check if next character is part of pattern */
607
341M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
334M
                i = i + m;
609
334M
            }
610
341M
        }
611
352M
    }
612
101k
    return mode == FAST_COUNT ? count : -1;
613
3.52M
}
unicodeobject.c:ucs4lib_default_find
Line
Count
Source
560
4.26M
{
561
4.26M
    const Py_ssize_t w = n - m;
562
4.26M
    Py_ssize_t mlast = m - 1, count = 0;
563
4.26M
    Py_ssize_t gap = mlast;
564
4.26M
    const STRINGLIB_CHAR last = p[mlast];
565
4.26M
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
4.26M
    unsigned long mask = 0;
568
8.60M
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
4.34M
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
4.34M
        if (p[i] == last) {
571
18.5k
            gap = mlast - i - 1;
572
18.5k
        }
573
4.34M
    }
574
4.26M
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
212M
    for (Py_ssize_t i = 0; i <= w; i++) {
577
212M
        if (ss[i] == last) {
578
            /* candidate match */
579
13.2M
            Py_ssize_t j;
580
21.6M
            for (j = 0; j < mlast; j++) {
581
13.3M
                if (s[i+j] != p[j]) {
582
4.86M
                    break;
583
4.86M
                }
584
13.3M
            }
585
13.2M
            if (j == mlast) {
586
                /* got a match! */
587
8.36M
                if (mode != FAST_COUNT) {
588
4.23M
                    return i;
589
4.23M
                }
590
4.13M
                count++;
591
4.13M
                if (count == maxcount) {
592
0
                    return maxcount;
593
0
                }
594
4.13M
                i = i + mlast;
595
4.13M
                continue;
596
4.13M
            }
597
            /* miss: check if next character is part of pattern */
598
4.86M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
1.60M
                i = i + m;
600
1.60M
            }
601
3.25M
            else {
602
3.25M
                i = i + gap;
603
3.25M
            }
604
4.86M
        }
605
199M
        else {
606
            /* skip: check if next character is part of pattern */
607
199M
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
193M
                i = i + m;
609
193M
            }
610
199M
        }
611
212M
    }
612
29.5k
    return mode == FAST_COUNT ? count : -1;
613
4.26M
}
bytes_methods.c:stringlib_default_find
Line
Count
Source
560
1.16k
{
561
1.16k
    const Py_ssize_t w = n - m;
562
1.16k
    Py_ssize_t mlast = m - 1, count = 0;
563
1.16k
    Py_ssize_t gap = mlast;
564
1.16k
    const STRINGLIB_CHAR last = p[mlast];
565
1.16k
    const STRINGLIB_CHAR *const ss = &s[mlast];
566
567
1.16k
    unsigned long mask = 0;
568
4.67k
    for (Py_ssize_t i = 0; i < mlast; i++) {
569
3.50k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
570
3.50k
        if (p[i] == last) {
571
1.16k
            gap = mlast - i - 1;
572
1.16k
        }
573
3.50k
    }
574
1.16k
    STRINGLIB_BLOOM_ADD(mask, last);
575
576
225k
    for (Py_ssize_t i = 0; i <= w; i++) {
577
225k
        if (ss[i] == last) {
578
            /* candidate match */
579
3.80k
            Py_ssize_t j;
580
7.10k
            for (j = 0; j < mlast; j++) {
581
6.13k
                if (s[i+j] != p[j]) {
582
2.84k
                    break;
583
2.84k
                }
584
6.13k
            }
585
3.80k
            if (j == mlast) {
586
                /* got a match! */
587
969
                if (mode != FAST_COUNT) {
588
969
                    return i;
589
969
                }
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.84k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
599
900
                i = i + m;
600
900
            }
601
1.94k
            else {
602
1.94k
                i = i + gap;
603
1.94k
            }
604
2.84k
        }
605
221k
        else {
606
            /* skip: check if next character is part of pattern */
607
221k
            if (i + 1 <= w && !STRINGLIB_BLOOM(mask, ss[i+1])) {
608
216k
                i = i + m;
609
216k
            }
610
221k
        }
611
225k
    }
612
200
    return mode == FAST_COUNT ? count : -1;
613
1.16k
}
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.22k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.22k
    unsigned long mask = 0;
696
7.22k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.22k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
28.9k
    for (i = mlast; i > 0; i--) {
702
21.6k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.6k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.6k
    }
707
708
1.58M
    for (i = w; i >= 0; i--) {
709
1.58M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
86.6k
            for (j = mlast; j > 0; j--) {
712
79.5k
                if (s[i+j] != p[j]) {
713
57.5k
                    break;
714
57.5k
                }
715
79.5k
            }
716
64.6k
            if (j == 0) {
717
                /* got a match! */
718
7.10k
                return i;
719
7.10k
            }
720
            /* miss: check if previous character is part of pattern */
721
57.5k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
55.8k
                i = i - m;
723
55.8k
            }
724
1.65k
            else {
725
1.65k
                i = i - skip;
726
1.65k
            }
727
57.5k
        }
728
1.51M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.51M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.29M
                i = i - m;
732
1.29M
            }
733
1.51M
        }
734
1.58M
    }
735
119
    return -1;
736
7.22k
}
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.22k
{
694
    /* create compressed boyer-moore delta 1 table */
695
7.22k
    unsigned long mask = 0;
696
7.22k
    Py_ssize_t i, j, mlast = m - 1, skip = m - 1, w = n - m;
697
698
    /* process pattern[0] outside the loop */
699
7.22k
    STRINGLIB_BLOOM_ADD(mask, p[0]);
700
    /* process pattern[:0:-1] */
701
28.9k
    for (i = mlast; i > 0; i--) {
702
21.6k
        STRINGLIB_BLOOM_ADD(mask, p[i]);
703
21.6k
        if (p[i] == p[0]) {
704
0
            skip = i - 1;
705
0
        }
706
21.6k
    }
707
708
1.58M
    for (i = w; i >= 0; i--) {
709
1.58M
        if (s[i] == p[0]) {
710
            /* candidate match */
711
86.6k
            for (j = mlast; j > 0; j--) {
712
79.5k
                if (s[i+j] != p[j]) {
713
57.5k
                    break;
714
57.5k
                }
715
79.5k
            }
716
64.6k
            if (j == 0) {
717
                /* got a match! */
718
7.10k
                return i;
719
7.10k
            }
720
            /* miss: check if previous character is part of pattern */
721
57.5k
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
722
55.8k
                i = i - m;
723
55.8k
            }
724
1.65k
            else {
725
1.65k
                i = i - skip;
726
1.65k
            }
727
57.5k
        }
728
1.51M
        else {
729
            /* skip: check if previous character is part of pattern */
730
1.51M
            if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) {
731
1.29M
                i = i - m;
732
1.29M
            }
733
1.51M
        }
734
1.58M
    }
735
119
    return -1;
736
7.22k
}
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
39.6M
{
762
39.6M
    Py_ssize_t count = 0;
763
5.22G
    for (Py_ssize_t i = 0; i < n; i++) {
764
5.18G
        if (s[i] == p0) {
765
894M
            count++;
766
894M
        }
767
5.18G
    }
768
39.6M
    return count;
769
39.6M
}
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
25.5M
{
762
25.5M
    Py_ssize_t count = 0;
763
693M
    for (Py_ssize_t i = 0; i < n; i++) {
764
667M
        if (s[i] == p0) {
765
36.5M
            count++;
766
36.5M
        }
767
667M
    }
768
25.5M
    return count;
769
25.5M
}
unicodeobject.c:ucs2lib_count_char_no_maxcount
Line
Count
Source
761
4.70M
{
762
4.70M
    Py_ssize_t count = 0;
763
724M
    for (Py_ssize_t i = 0; i < n; i++) {
764
719M
        if (s[i] == p0) {
765
18.9M
            count++;
766
18.9M
        }
767
719M
    }
768
4.70M
    return count;
769
4.70M
}
unicodeobject.c:ucs4lib_count_char_no_maxcount
Line
Count
Source
761
2.81M
{
762
2.81M
    Py_ssize_t count = 0;
763
460M
    for (Py_ssize_t i = 0; i < n; i++) {
764
457M
        if (s[i] == p0) {
765
13.4M
            count++;
766
13.4M
        }
767
457M
    }
768
2.81M
    return count;
769
2.81M
}
bytes_methods.c:stringlib_count_char_no_maxcount
Line
Count
Source
761
6.52M
{
762
6.52M
    Py_ssize_t count = 0;
763
3.34G
    for (Py_ssize_t i = 0; i < n; i++) {
764
3.33G
        if (s[i] == p0) {
765
825M
            count++;
766
825M
        }
767
3.33G
    }
768
6.52M
    return count;
769
6.52M
}
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
99.5M
{
777
99.5M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
452
        return -1;
779
452
    }
780
781
    /* look for special cases */
782
99.5M
    if (m <= 1) {
783
62.4M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
62.4M
        if (mode == FAST_SEARCH)
788
22.7M
            return STRINGLIB(find_char)(s, n, p[0]);
789
39.6M
        else if (mode == FAST_RSEARCH)
790
50.2k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
39.6M
        else {
792
39.6M
            if (maxcount == PY_SSIZE_T_MAX) {
793
39.6M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
39.6M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
39.6M
        }
797
62.4M
    }
798
799
37.1M
    if (mode != FAST_RSEARCH) {
800
37.1M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
37.1M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
37.1M
        }
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
37.1M
    }
825
7.22k
    else {
826
        /* FAST_RSEARCH */
827
7.22k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.22k
    }
829
37.1M
}
bytesobject.c:fastsearch
Line
Count
Source
776
515k
{
777
515k
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
515k
    if (m <= 1) {
783
515k
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
515k
        if (mode == FAST_SEARCH)
788
515k
            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
515k
    }
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.18M
{
777
8.18M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
8.18M
    if (m <= 1) {
783
5.80M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
5.80M
        if (mode == FAST_SEARCH)
788
5.75M
            return STRINGLIB(find_char)(s, n, p[0]);
789
50.2k
        else if (mode == FAST_RSEARCH)
790
50.2k
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
0
        else {
792
0
            if (maxcount == PY_SSIZE_T_MAX) {
793
0
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
0
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
0
        }
797
5.80M
    }
798
799
2.38M
    if (mode != FAST_RSEARCH) {
800
2.38M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
2.38M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
2.38M
        }
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.38M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
2.38M
}
unicodeobject.c:ucs1lib_fastsearch
Line
Count
Source
776
61.0M
{
777
61.0M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
61.0M
    if (m <= 1) {
783
34.0M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
34.0M
        if (mode == FAST_SEARCH)
788
8.48M
            return STRINGLIB(find_char)(s, n, p[0]);
789
25.5M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
25.5M
        else {
792
25.5M
            if (maxcount == PY_SSIZE_T_MAX) {
793
25.5M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
25.5M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
25.5M
        }
797
34.0M
    }
798
799
26.9M
    if (mode != FAST_RSEARCH) {
800
26.9M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
26.9M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
26.9M
        }
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
26.9M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
26.9M
}
unicodeobject.c:ucs2lib_fastsearch
Line
Count
Source
776
12.1M
{
777
12.1M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
447
        return -1;
779
447
    }
780
781
    /* look for special cases */
782
12.1M
    if (m <= 1) {
783
8.64M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
8.64M
        if (mode == FAST_SEARCH)
788
3.94M
            return STRINGLIB(find_char)(s, n, p[0]);
789
4.70M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
4.70M
        else {
792
4.70M
            if (maxcount == PY_SSIZE_T_MAX) {
793
4.70M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
4.70M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
4.70M
        }
797
8.64M
    }
798
799
3.52M
    if (mode != FAST_RSEARCH) {
800
3.52M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
3.52M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
3.52M
        }
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.52M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
3.52M
}
unicodeobject.c:ucs4lib_fastsearch
Line
Count
Source
776
11.1M
{
777
11.1M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
0
        return -1;
779
0
    }
780
781
    /* look for special cases */
782
11.1M
    if (m <= 1) {
783
6.86M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
6.86M
        if (mode == FAST_SEARCH)
788
4.04M
            return STRINGLIB(find_char)(s, n, p[0]);
789
2.81M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
2.81M
        else {
792
2.81M
            if (maxcount == PY_SSIZE_T_MAX) {
793
2.81M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
2.81M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
2.81M
        }
797
6.86M
    }
798
799
4.26M
    if (mode != FAST_RSEARCH) {
800
4.26M
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
4.26M
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
4.26M
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
4.26M
    }
825
0
    else {
826
        /* FAST_RSEARCH */
827
0
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
0
    }
829
4.26M
}
bytes_methods.c:fastsearch
Line
Count
Source
776
6.52M
{
777
6.52M
    if (n < m || (mode == FAST_COUNT && maxcount == 0)) {
778
5
        return -1;
779
5
    }
780
781
    /* look for special cases */
782
6.52M
    if (m <= 1) {
783
6.52M
        if (m <= 0) {
784
0
            return -1;
785
0
        }
786
        /* use special case for 1-character strings */
787
6.52M
        if (mode == FAST_SEARCH)
788
0
            return STRINGLIB(find_char)(s, n, p[0]);
789
6.52M
        else if (mode == FAST_RSEARCH)
790
0
            return STRINGLIB(rfind_char)(s, n, p[0]);
791
6.52M
        else {
792
6.52M
            if (maxcount == PY_SSIZE_T_MAX) {
793
6.52M
                return STRINGLIB(count_char_no_maxcount)(s, n, p[0]);
794
6.52M
            }
795
0
            return STRINGLIB(count_char)(s, n, p[0], maxcount);
796
6.52M
        }
797
6.52M
    }
798
799
8.39k
    if (mode != FAST_RSEARCH) {
800
1.16k
        if (n < 2500 || (m < 100 && n < 30000) || m < 6) {
801
1.16k
            return STRINGLIB(default_find)(s, n, p, m, maxcount, mode);
802
1.16k
        }
803
0
        else if ((m >> 2) * 3 < (n >> 2)) {
804
            /* 33% threshold, but don't overflow. */
805
            /* For larger problems where the needle isn't a huge
806
               percentage of the size of the haystack, the relatively
807
               expensive O(m) startup cost of the two-way algorithm
808
               will surely pay off. */
809
0
            if (mode == FAST_SEARCH) {
810
0
                return STRINGLIB(_two_way_find)(s, n, p, m);
811
0
            }
812
0
            else {
813
0
                return STRINGLIB(_two_way_count)(s, n, p, m, maxcount);
814
0
            }
815
0
        }
816
0
        else {
817
            /* To ensure that we have good worst-case behavior,
818
               here's an adaptive version of the algorithm, where if
819
               we match O(m) characters without any matches of the
820
               entire needle, then we predict that the startup cost of
821
               the two-way algorithm will probably be worth it. */
822
0
            return STRINGLIB(adaptive_find)(s, n, p, m, maxcount, mode);
823
0
        }
824
1.16k
    }
825
7.22k
    else {
826
        /* FAST_RSEARCH */
827
7.22k
        return STRINGLIB(default_rfind)(s, n, p, m, maxcount, mode);
828
7.22k
    }
829
8.39k
}
Unexecuted instantiation: bytearrayobject.c:fastsearch
830