8080#endif
8181#include " tier0/memdbgon.h"
8282
83- static int FastToLower ( char c )
84- {
85- int i = ( unsigned char ) c;
86- if ( i < 0x80 )
87- {
88- // Brutally fast branchless ASCII tolower():
89- i += (((( ' A ' - 1 ) - i) & (i - ( ' Z ' + 1 ))) >> 26 ) & 0x20 ;
90- }
91- else
92- {
93- i += isupper ( i ) ? 0x20 : 0 ;
94- }
95- return i;
96- }
83+ # define USE_FAST_CASE_CONVERSION 1
84+ # if USE_FAST_CASE_CONVERSION
85+ // / Faster conversion of an ascii char to upper case. This function does not obey locale or any language
86+ // / setting. It should not be used to convert characters for printing, but it is a better choice
87+ // / for internal strings such as used for hash table keys, etc. It's meant to be inlined and used
88+ // / in places like the various dictionary classes. Not obeying locale also protects you from things
89+ // / like your hash values being different depending on the locale setting.
90+ # define FastASCIIToUpper ( c ) ( ( ( (c) >= ' a ' ) && ( (c) <= ' z ' ) ) ? ( (c) - 32 ) : (c) )
91+ // / similar to FastASCIIToLower
92+ # define FastASCIIToLower ( c ) ( ( ( (c) >= ' A ' ) && ( (c) <= ' Z ' ) ) ? ( (c) + 32 ) : (c) )
93+ # else
94+ # define FastASCIIToLower tolower
95+ # define FastASCIIToUpper toupper
96+ # endif
9797
9898void _V_memset (const char * file, int line, void *dest, int fill, int count)
9999{
@@ -260,6 +260,17 @@ char *V_strnlwr(char *s, size_t count)
260260 return pRet;
261261}
262262
263+ static constexpr uint8 lowerAsciiLookup[128 ] = {
264+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 , 0x08 , 0x09 , 0x0A , 0x0B , 0x0C , 0x0D , 0x0E , 0x0F ,
265+ 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 , 0x18 , 0x19 , 0x1A , 0x1B , 0x1C , 0x1D , 0x1E , 0x1F ,
266+ 0x20 , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 , 0x27 , 0x28 , 0x29 , 0x2A , 0x2B , 0x2C , 0x2D , 0x2E , 0x2F ,
267+ 0x30 , 0x31 , 0x32 , 0x33 , 0x34 , 0x35 , 0x36 , 0x37 , 0x38 , 0x39 , 0x3A , 0x3B , 0x3C , 0x3D , 0x3E , 0x3F ,
268+ 0x40 , ' a' , ' b' , ' c' , ' d' , ' e' , ' f' , ' g' , ' h' , ' i' , ' j' , ' k' , ' l' , ' m' , ' n' , ' o' ,
269+ ' p' , ' q' , ' r' , ' s' , ' t' , ' u' , ' v' , ' w' , ' x' , ' y' , ' z' , 0x5B , 0x5C , 0x5D , 0x5E , 0x5F ,
270+ 0x60 , 0x61 , 0x62 , 0x63 , 0x64 , 0x65 , 0x66 , 0x67 , 0x68 , 0x69 , 0x6A , 0x6B , 0x6C , 0x6D , 0x6E , 0x6F ,
271+ 0x70 , 0x71 , 0x72 , 0x73 , 0x74 , 0x75 , 0x76 , 0x77 , 0x78 , 0x79 , 0x7A , 0x7B , 0x7C , 0x7D , 0x7E , 0x7F
272+ };
273+
263274int V_stricmp ( const char *str1, const char *str2 )
264275{
265276 // It is not uncommon to compare a string to itself. See
@@ -272,6 +283,7 @@ int V_stricmp( const char *str1, const char *str2 )
272283 }
273284 const unsigned char *s1 = (const unsigned char *)str1;
274285 const unsigned char *s2 = (const unsigned char *)str2;
286+ #if 0
275287 for ( ; *s1; ++s1, ++s2 )
276288 {
277289 if ( *s1 != *s2 )
@@ -291,6 +303,31 @@ int V_stricmp( const char *str1, const char *str2 )
291303 }
292304 }
293305 return *s2 ? -1 : 0;
306+ #else
307+ while (true )
308+ {
309+ unsigned char c1 = *s1++;
310+ unsigned char c2 = *s2++;
311+ if (c1 == c2)
312+ {
313+ if ( !c1 ) return 0 ;
314+ }
315+ else if ((((uint32)c1 | (uint32)c2) & 0xffffff80 ) == 0 )
316+ {
317+ if (int32 res = lowerAsciiLookup[c1] - lowerAsciiLookup[c2])
318+ {
319+ return res;
320+ }
321+ }
322+ else
323+ {
324+ if (int32 res = tolower (c1) - tolower (c2))
325+ {
326+ return res;
327+ }
328+ }
329+ }
330+ #endif
294331}
295332
296333int V_strnicmp ( const char *str1, const char *str2, int n )
@@ -348,7 +385,7 @@ const char *StringAfterPrefix( const char *str, const char *prefix )
348385 if ( !*prefix )
349386 return str;
350387 }
351- while ( FastToLower ( *str++ ) == FastToLower ( *prefix++ ) );
388+ while ( tolower ( *str++ ) == tolower ( *prefix++ ) );
352389 return NULL ;
353390}
354391
@@ -638,7 +675,7 @@ char const* V_stristr( char const* pStr, char const* pSearch )
638675 while (*pLetter != 0 )
639676 {
640677 // Skip over non-matches
641- if (FastToLower ((unsigned char )*pLetter) == FastToLower ((unsigned char )*pSearch))
678+ if (FastASCIIToLower ((unsigned char )*pLetter) == FastASCIIToLower ((unsigned char )*pSearch))
642679 {
643680 // Check for match
644681 char const * pMatch = pLetter + 1 ;
@@ -649,7 +686,7 @@ char const* V_stristr( char const* pStr, char const* pSearch )
649686 if (*pMatch == 0 )
650687 return 0 ;
651688
652- if (FastToLower ((unsigned char )*pMatch) != FastToLower ((unsigned char )*pTest))
689+ if (FastASCIIToLower ((unsigned char )*pMatch) != FastASCIIToLower ((unsigned char )*pTest))
653690 break ;
654691
655692 ++pMatch;
@@ -696,7 +733,7 @@ char const* V_strnistr( char const* pStr, char const* pSearch, int n )
696733 return 0 ;
697734
698735 // Skip over non-matches
699- if (FastToLower (*pLetter) == FastToLower (*pSearch))
736+ if (FastASCIIToLower (*pLetter) == FastASCIIToLower (*pSearch))
700737 {
701738 int n1 = n - 1 ;
702739
@@ -712,7 +749,7 @@ char const* V_strnistr( char const* pStr, char const* pSearch, int n )
712749 if (*pMatch == 0 )
713750 return 0 ;
714751
715- if (FastToLower (*pMatch) != FastToLower (*pTest))
752+ if (FastASCIIToLower (*pMatch) != FastASCIIToLower (*pTest))
716753 break ;
717754
718755 ++pMatch;
@@ -1421,7 +1458,7 @@ int _V_UCS2ToUnicode( const ucs2 *pUCS2, wchar_t *pUnicode, int cubDestSizeInByt
14211458 size_t nMaxUTF8 = cubDestSizeInBytes;
14221459 char *pIn = (char *)pUCS2;
14231460 char *pOut = (char *)pUnicode;
1424- if ( conv_t > 0 )
1461+ if ( conv_t != nullptr )
14251462 {
14261463 cchResult = iconv ( conv_t , &pIn, &nLenUnicde, &pOut, &nMaxUTF8 );
14271464 iconv_close ( conv_t );
@@ -1461,7 +1498,7 @@ int _V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, char *pUCS2, i
14611498 size_t nMaxUCS2 = cubDestSizeInBytes;
14621499 char *pIn = (char *)pUnicode;
14631500 char *pOut = pUCS2;
1464- if ( conv_t > 0 )
1501+ if ( conv_t != nullptr )
14651502 {
14661503 cchResult = iconv ( conv_t , &pIn, &nLenUnicde, &pOut, &nMaxUCS2 );
14671504 iconv_close ( conv_t );
@@ -1509,7 +1546,7 @@ int _V_UCS2ToUTF8( const ucs2 *pUCS2, char *pUTF8, int cubDestSizeInBytes )
15091546 size_t nMaxUTF8 = cubDestSizeInBytes - 1 ;
15101547 char *pIn = (char *)pUCS2;
15111548 char *pOut = (char *)pUTF8;
1512- if ( conv_t > 0 )
1549+ if ( conv_t != nullptr )
15131550 {
15141551 const size_t nBytesToWrite = nMaxUTF8;
15151552 cchResult = iconv ( conv_t , &pIn, &nLenUnicde, &pOut, &nMaxUTF8 );
@@ -1554,7 +1591,7 @@ int _V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, ucs2 *pUCS2, int cubDes
15541591 size_t nMaxUTF8 = cubDestSizeInBytes;
15551592 char *pIn = (char *)pUTF8;
15561593 char *pOut = (char *)pUCS2;
1557- if ( conv_t > 0 )
1594+ if ( conv_t != nullptr )
15581595 {
15591596 cchResult = iconv ( conv_t , &pIn, &nLenUnicde, &pOut, &nMaxUTF8 );
15601597 iconv_close ( conv_t );
@@ -2275,7 +2312,7 @@ bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pR
22752312 // Strip out common parts of the path
22762313 const char *pLastCommonPath = NULL ;
22772314 const char *pLastCommonDir = NULL ;
2278- while ( *pPath && ( FastToLower ( *pPath ) == FastToLower ( *pDir ) ||
2315+ while ( *pPath && ( tolower ( *pPath ) == tolower ( *pDir ) ||
22792316 ( PATHSEPARATOR ( *pPath ) && ( PATHSEPARATOR ( *pDir ) || (*pDir == 0 ) ) ) ) )
22802317 {
22812318 if ( PATHSEPARATOR ( *pPath ) )
0 commit comments