3232#define STRINGLIB_BLOOM (mask , ch ) \
3333 ((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1)))))
3434
35+ #if STRINGLIB_SIZEOF_CHAR == 1
36+ # define MEMCHR_CUT_OFF 15
37+ #else
38+ # define MEMCHR_CUT_OFF 40
39+ #endif
40+
3541Py_LOCAL_INLINE (Py_ssize_t )
3642STRINGLIB (find_char )(const STRINGLIB_CHAR * s , Py_ssize_t n , STRINGLIB_CHAR ch )
3743{
3844 const STRINGLIB_CHAR * p , * e ;
3945
4046 p = s ;
4147 e = s + n ;
42- if (n > 10 ) {
48+ if (n > MEMCHR_CUT_OFF ) {
4349#if STRINGLIB_SIZEOF_CHAR == 1
4450 p = memchr (s , ch , n );
4551 if (p != NULL )
@@ -48,24 +54,36 @@ STRINGLIB(find_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
4854#else
4955 /* use memchr if we can choose a needle without two many likely
5056 false positives */
57+ const STRINGLIB_CHAR * s1 , * e1 ;
5158 unsigned char needle = ch & 0xff ;
5259 /* If looking for a multiple of 256, we'd have too
5360 many false positives looking for the '\0' byte in UCS2
5461 and UCS4 representations. */
5562 if (needle != 0 ) {
56- while ( p < e ) {
63+ do {
5764 void * candidate = memchr (p , needle ,
5865 (e - p ) * sizeof (STRINGLIB_CHAR ));
5966 if (candidate == NULL )
6067 return -1 ;
68+ s1 = p ;
6169 p = (const STRINGLIB_CHAR * )
6270 _Py_ALIGN_DOWN (candidate , sizeof (STRINGLIB_CHAR ));
6371 if (* p == ch )
6472 return (p - s );
6573 /* False positive */
6674 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+ }
6785 }
68- return -1 ;
86+ while ( e - p > MEMCHR_CUT_OFF ) ;
6987 }
7088#endif
7189 }
@@ -86,7 +104,7 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
86104 it doesn't seem as optimized as memchr(), but is still quite
87105 faster than our hand-written loop below */
88106
89- if (n > 10 ) {
107+ if (n > MEMCHR_CUT_OFF ) {
90108#if STRINGLIB_SIZEOF_CHAR == 1
91109 p = memrchr (s , ch , n );
92110 if (p != NULL )
@@ -95,24 +113,38 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
95113#else
96114 /* use memrchr if we can choose a needle without two many likely
97115 false positives */
116+ const STRINGLIB_CHAR * s1 ;
117+ Py_ssize_t n1 ;
98118 unsigned char needle = ch & 0xff ;
99119 /* If looking for a multiple of 256, we'd have too
100120 many false positives looking for the '\0' byte in UCS2
101121 and UCS4 representations. */
102122 if (needle != 0 ) {
103- while ( n > 0 ) {
123+ do {
104124 void * candidate = memrchr (s , needle ,
105125 n * sizeof (STRINGLIB_CHAR ));
106126 if (candidate == NULL )
107127 return -1 ;
128+ n1 = n ;
108129 p = (const STRINGLIB_CHAR * )
109130 _Py_ALIGN_DOWN (candidate , sizeof (STRINGLIB_CHAR ));
110131 n = p - s ;
111132 if (* p == ch )
112133 return n ;
113134 /* 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 ;
114146 }
115- return -1 ;
147+ while ( n > MEMCHR_CUT_OFF ) ;
116148 }
117149#endif
118150 }
@@ -126,6 +158,8 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch)
126158 return -1 ;
127159}
128160
161+ #undef MEMCHR_CUT_OFF
162+
129163Py_LOCAL_INLINE (Py_ssize_t )
130164FASTSEARCH (const STRINGLIB_CHAR * s , Py_ssize_t n ,
131165 const STRINGLIB_CHAR * p , Py_ssize_t m ,
0 commit comments