1212
1313/* Mask to quickly check whether a C 'size_t' contains a
1414 non-ASCII, UTF8-encoded char. */
15-
1615#if STRINGLIB_SIZEOF_CHAR == 1
1716# if SIZEOF_SIZE_T == 8
1817# define MASK_ASCII 0x8080808080808080ULL
5352#error Invalid STRINGLIB_SIZEOF_CHAR (must be 1, 2 or 4)
5453#endif
5554
55+ /* OR all characters into a single size_t accumulator and test the high bits
56+ at the end, instead of comparing each character. The accumulation loop has
57+ no branches, so compilers vectorize it, and the result does not depend on
58+ where each byte sits in the word, so unaligned ends can be read in smaller
59+ pieces. Every 32 words, check whether the widest kind is already known and
60+ exit early. */
5661Py_LOCAL_INLINE (Py_UCS4 )
5762STRINGLIB (find_max_char )(const STRINGLIB_CHAR * begin , const STRINGLIB_CHAR * end )
5863{
@@ -63,18 +68,18 @@ STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
6368
6469 if (!_Py_IS_ALIGNED (p , ALIGNOF_SIZE_T )) {
6570#if STRINGLIB_SIZEOF_CHAR <= 1
66- if (!_Py_IS_ALIGNED (p , 1 ) && p + 1 <= _end ) {
71+ if (!_Py_IS_ALIGNED (p , sizeof ( uint16_t ) ) && p + 1 <= _end ) {
6772 value |= * p ++ ;
6873 }
6974#endif
7075#if STRINGLIB_SIZEOF_CHAR <= 2
71- if (!_Py_IS_ALIGNED (p , sizeof (uint16_t )) && p + sizeof (uint16_t ) <= _end ) {
76+ if (!_Py_IS_ALIGNED (p , sizeof (uint32_t )) && p + sizeof (uint16_t ) <= _end ) {
7277 value |= * (const uint16_t * )p ;
7378 p += sizeof (uint16_t );
7479 }
7580#endif
7681#if SIZEOF_SIZE_T == 8
77- if (!_Py_IS_ALIGNED (p , sizeof ( uint32_t ) ) && p + sizeof (uint32_t ) <= _end ) {
82+ if (!_Py_IS_ALIGNED (p , SIZEOF_SIZE_T ) && p + sizeof (uint32_t ) <= _end ) {
7883 value |= * (const uint32_t * )p ;
7984 p += sizeof (uint32_t );
8085 }
@@ -83,7 +88,7 @@ STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
8388
8489 while (p + SIZEOF_SIZE_T * 32 <= _end ) {
8590 const size_t * pp = (const size_t * )p ;
86- for (int i = 0 ; i < 32 ; i ++ ) {
91+ for (int i = 0 ; i < 32 ; i ++ ) {
8792 value |= pp [i ];
8893 }
8994 if (value & MASK_MAX_CHAR ) {
@@ -115,15 +120,18 @@ STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end)
115120#endif
116121
117122#ifdef MASK_UCS2
118- if (value & MASK_UCS2 )
123+ if (value & MASK_UCS2 ) {
119124 return MAX_CHAR_UCS4 ;
125+ }
120126#endif
121127#ifdef MASK_UCS1
122- if (value & MASK_UCS1 )
128+ if (value & MASK_UCS1 ) {
123129 return MAX_CHAR_UCS2 ;
130+ }
124131#endif
125- if (value & MASK_ASCII )
132+ if (value & MASK_ASCII ) {
126133 return MAX_CHAR_UCS1 ;
134+ }
127135 return MAX_CHAR_ASCII ;
128136}
129137
0 commit comments