diff options
Diffstat (limited to 'zen/zstring.cpp')
-rw-r--r-- | zen/zstring.cpp | 120 |
1 files changed, 53 insertions, 67 deletions
diff --git a/zen/zstring.cpp b/zen/zstring.cpp index 59f15f19..6d249e70 100644 --- a/zen/zstring.cpp +++ b/zen/zstring.cpp @@ -8,8 +8,7 @@ #include <stdexcept> #ifdef ZEN_WIN - #include "dll.h" - //#include "win_ver.h" + #include "win.h" #endif using namespace zen; @@ -37,80 +36,67 @@ time per call | function #ifdef ZEN_WIN -namespace -{ -//try to call "CompareStringOrdinal" for low-level string comparison: unfortunately available not before Windows Vista! -//by a factor ~3 faster than old string comparison using "LCMapString" -typedef int (WINAPI* CompareStringOrdinalFunc)(LPCWSTR lpString1, int cchCount1, - LPCWSTR lpString2, int cchCount2, BOOL bIgnoreCase); -const SysDllFun<CompareStringOrdinalFunc> compareStringOrdinal = SysDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); -//watch for dependencies in global namespace!!! -} - - int cmpStringNoCase(const wchar_t* lhs, size_t lhsLen, const wchar_t* rhs, size_t rhsLen) { assert(std::find(lhs, lhs + lhsLen, 0) == lhs + lhsLen); //don't expect embedded nulls! assert(std::find(rhs, rhs + rhsLen, 0) == rhs + rhsLen); // - if (compareStringOrdinal) //this additional test has no noticeable performance impact +#ifdef ZEN_WIN_VISTA_AND_LATER + //"CompareStringOrdinal" (available since Windows Vista) is by a factor ~3 faster than old string comparison using "LCMapString" + const int rv = ::CompareStringOrdinal(lhs, //__in LPCWSTR lpString1, + static_cast<int>(lhsLen), //__in int cchCount1, + rhs, //__in LPCWSTR lpString2, + static_cast<int>(rhsLen), //__in int cchCount2, + true); //__in BOOL bIgnoreCase + if (rv <= 0) + throw std::runtime_error("Error comparing strings (CompareStringOrdinal). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); + else + return rv - 2; //convert to C-style string compare result +#else + //do NOT use "CompareString"; this function is NOT meant for file name comparisons (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!! + //the only reliable way to compare filepaths (with XP) is to call "CharUpper" or "LCMapString": + + const auto minSize = std::min(lhsLen, rhsLen); + + if (minSize == 0) //LCMapString does not allow input sizes of 0! + return static_cast<int>(lhsLen) - static_cast<int>(rhsLen); + + auto copyToUpperCase = [minSize](const wchar_t* strIn, wchar_t* strOut) + { + //faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString() + if (::LCMapString(LOCALE_INVARIANT, //__in LCID Locale, + LCMAP_UPPERCASE, //__in DWORD dwMapFlags, + strIn, //__in LPCTSTR lpSrcStr, + static_cast<int>(minSize), //__in int cchSrc, + strOut, //__out LPTSTR lpDestStr, + static_cast<int>(minSize)) == 0) //__in int cchDest + throw std::runtime_error("Error comparing strings (LCMapString). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); + }; + + auto eval = [&](wchar_t* bufL, wchar_t* bufR) + { + copyToUpperCase(lhs, bufL); + copyToUpperCase(rhs, bufR); + + const int rv = ::wcsncmp(bufL, bufR, minSize); + if (rv != 0) + return rv; + + return static_cast<int>(lhsLen) - static_cast<int>(rhsLen); + }; + + if (minSize <= MAX_PATH) //performance optimization: stack { - const int rv = compareStringOrdinal(lhs, //__in LPCWSTR lpString1, - static_cast<int>(lhsLen), //__in int cchCount1, - rhs, //__in LPCWSTR lpString2, - static_cast<int>(rhsLen), //__in int cchCount2, - true); //__in BOOL bIgnoreCase - if (rv <= 0) - throw std::runtime_error("Error comparing strings (CompareStringOrdinal). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); - else - return rv - 2; //convert to C-style string compare result + wchar_t bufferL[MAX_PATH] = {}; + wchar_t bufferR[MAX_PATH] = {}; + return eval(bufferL, bufferR); } - else //fallback + else //use freestore { - //do NOT use "CompareString"; this function is NOT accurate (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!! - //the only reliable way to compare filepaths (with XP) is to call "CharUpper" or "LCMapString": - - const auto minSize = std::min(lhsLen, rhsLen); - - if (minSize == 0) //LCMapString does not allow input sizes of 0! - return static_cast<int>(lhsLen) - static_cast<int>(rhsLen); - - auto copyToUpperCase = [minSize](const wchar_t* strIn, wchar_t* strOut) - { - //faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString() - if (::LCMapString(LOCALE_INVARIANT, //__in LCID Locale, - LCMAP_UPPERCASE, //__in DWORD dwMapFlags, - strIn, //__in LPCTSTR lpSrcStr, - static_cast<int>(minSize), //__in int cchSrc, - strOut, //__out LPTSTR lpDestStr, - static_cast<int>(minSize)) == 0) //__in int cchDest - throw std::runtime_error("Error comparing strings (LCMapString). " + std::string(__FILE__) + ":" + numberTo<std::string>(__LINE__)); - }; - - auto eval = [&](wchar_t* bufL, wchar_t* bufR) - { - copyToUpperCase(lhs, bufL); - copyToUpperCase(rhs, bufR); - - const int rv = ::wcsncmp(bufL, bufR, minSize); - if (rv != 0) - return rv; - - return static_cast<int>(lhsLen) - static_cast<int>(rhsLen); - }; - - if (minSize <= MAX_PATH) //performance optimization: stack - { - wchar_t bufferL[MAX_PATH] = {}; - wchar_t bufferR[MAX_PATH] = {}; - return eval(bufferL, bufferR); - } - else //use freestore - { - std::vector<wchar_t> buffer(2 * minSize); - return eval(&buffer[0], &buffer[minSize]); - } + std::vector<wchar_t> buffer(2 * minSize); + return eval(&buffer[0], &buffer[minSize]); } +#endif } |