32
32
#define STRINGLIB_BLOOM (mask , ch ) \
33
33
((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
34
34
35
+ #if STRINGLIB_SIZEOF_CHAR == 1
36
+ # define MEMCHR_CUT_OFF 15
37
+ #else
38
+ # define MEMCHR_CUT_OFF 40
39
+ #endif
40
+
35
41
Py_LOCAL_INLINE (Py_ssize_t )
36
42
STRINGLIB (find_char )(const STRINGLIB_CHAR * s , Py_ssize_t n , STRINGLIB_CHAR ch )
37
43
{
38
44
const STRINGLIB_CHAR * p , * e ;
39
45
40
46
p = s ;
41
47
e = s + n ;
42
- if (n > 10 ) {
48
+ if (n > MEMCHR_CUT_OFF ) {
43
49
#if STRINGLIB_SIZEOF_CHAR == 1
44
50
p = memchr (s , ch , n );
45
51
if (p != NULL )
@@ -48,24 +54,36 @@ STRINGLIB(find_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
48
54
#else
49
55
/* use memchr if we can choose a needle without two many likely
50
56
false positives */
57
+ const STRINGLIB_CHAR * s1 , * e1 ;
51
58
unsigned char needle = ch & 0xff ;
52
59
/* If looking for a multiple of 256, we'd have too
53
60
many false positives looking for the '\0' byte in UCS2
54
61
and UCS4 representations. */
55
62
if (needle != 0 ) {
56
- while ( p < e ) {
63
+ do {
57
64
void * candidate = memchr (p , needle ,
58
65
(e - p ) * sizeof (STRINGLIB_CHAR ));
59
66
if (candidate == NULL )
60
67
return -1 ;
68
+ s1 = p ;
61
69
p = (const STRINGLIB_CHAR * )
62
70
_Py_ALIGN_DOWN (candidate , sizeof (STRINGLIB_CHAR ));
63
71
if (* p == ch )
64
72
return (p - s );
65
73
/* False positive */
66
74
p ++ ;
75
+ if (p - s1 > MEMCHR_CUT_OFF )
76
+ continue ;
77
+ if (e - p <= MEMCHR_CUT_OFF )
78
+ break ;
79
+ e1 = p + MEMCHR_CUT_OFF ;
80
+ while (p != e1 ) {
81
+ if (* p == ch )
82
+ return (p - s );
83
+ p ++ ;
84
+ }
67
85
}
68
- return -1 ;
86
+ while ( e - p > MEMCHR_CUT_OFF ) ;
69
87
}
70
88
#endif
71
89
}
@@ -86,7 +104,7 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
86
104
it doesn't seem as optimized as memchr(), but is still quite
87
105
faster than our hand-written loop below */
88
106
89
- if (n > 10 ) {
107
+ if (n > MEMCHR_CUT_OFF ) {
90
108
#if STRINGLIB_SIZEOF_CHAR == 1
91
109
p = memrchr (s , ch , n );
92
110
if (p != NULL )
@@ -95,24 +113,38 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
95
113
#else
96
114
/* use memrchr if we can choose a needle without two many likely
97
115
false positives */
116
+ const STRINGLIB_CHAR * s1 ;
117
+ Py_ssize_t n1 ;
98
118
unsigned char needle = ch & 0xff ;
99
119
/* If looking for a multiple of 256, we'd have too
100
120
many false positives looking for the '\0' byte in UCS2
101
121
and UCS4 representations. */
102
122
if (needle != 0 ) {
103
- while ( n > 0 ) {
123
+ do {
104
124
void * candidate = memrchr (s , needle ,
105
125
n * sizeof (STRINGLIB_CHAR ));
106
126
if (candidate == NULL )
107
127
return -1 ;
128
+ n1 = n ;
108
129
p = (const STRINGLIB_CHAR * )
109
130
_Py_ALIGN_DOWN (candidate , sizeof (STRINGLIB_CHAR ));
110
131
n = p - s ;
111
132
if (* p == ch )
112
133
return n ;
113
134
/* False positive */
135
+ if (n1 - n > MEMCHR_CUT_OFF )
136
+ continue ;
137
+ if (n <= MEMCHR_CUT_OFF )
138
+ break ;
139
+ s1 = p - MEMCHR_CUT_OFF ;
140
+ while (p > s1 ) {
141
+ p -- ;
142
+ if (* p == ch )
143
+ return (p - s );
144
+ }
145
+ n = p - s ;
114
146
}
115
- return -1 ;
147
+ while ( n > MEMCHR_CUT_OFF ) ;
116
148
}
117
149
#endif
118
150
}
@@ -126,6 +158,8 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
126
158
return -1 ;
127
159
}
128
160
161
+ #undef MEMCHR_CUT_OFF
162
+
129
163
Py_LOCAL_INLINE (Py_ssize_t )
130
164
FASTSEARCH (const STRINGLIB_CHAR * s , Py_ssize_t n ,
131
165
const STRINGLIB_CHAR * p , Py_ssize_t m ,
0 commit comments