From: Thomas Anderson Date: Wed, 27 Mar 2019 18:09:30 +0000 (+0000) Subject: Fix and speedup __libcpp_locale_guard on Windows X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=24812d8ac42e0c11f9c185282e4e4cc1d9b067a6;p=platform%2Fupstream%2Fllvm.git Fix and speedup __libcpp_locale_guard on Windows The old implementation assumed the POSIX `setlocale()` API where the old locale is returned. On Windows, the _new_ locale is returned. This meant that `__libcpp_locale_guard` wasn't resetting the locale on destruction. The new implementation fixes the above issue and takes advantage of `setlocale(LC_ALL)` to reduce the number of calls, and also avoids setting the locale at all if it's not necessary. Differential Revision: https://reviews.llvm.org/D59572 llvm-svn: 357104 --- diff --git a/libcxx/include/__locale b/libcxx/include/__locale index b79d78d..d9d2682 100644 --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -19,6 +19,7 @@ #include #include #if defined(_LIBCPP_MSVCRT_LIKE) +# include # include #elif defined(_AIX) # include @@ -63,28 +64,41 @@ private: #elif defined(_LIBCPP_MSVCRT_LIKE) struct __libcpp_locale_guard { __libcpp_locale_guard(locale_t __l) : - __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)), - __locale_collate(setlocale(LC_COLLATE, __l.__get_locale())), - __locale_ctype(setlocale(LC_CTYPE, __l.__get_locale())), - __locale_monetary(setlocale(LC_MONETARY, __l.__get_locale())), - __locale_numeric(setlocale(LC_NUMERIC, __l.__get_locale())), - __locale_time(setlocale(LC_TIME, __l.__get_locale())) - // LC_MESSAGES is not supported on Windows. - {} + __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) { + // Setting the locale can be expensive even when the locale given is + // already the current locale, so do an explicit check to see if the + // current locale is already the one we want. + const char* __lc = __setlocale(nullptr); + // If every category is the same, the locale string will simply be the + // locale name, otherwise it will be a semicolon-separated string listing + // each category. In the second case, we know at least one category won't + // be what we want, so we only have to check the first case. + if (strcmp(__l.__get_locale(), __lc) != 0) { + __locale_all = _strdup(__lc); + if (__locale_all == nullptr) + __throw_bad_alloc(); + __setlocale(__l.__get_locale()); + } + } ~__libcpp_locale_guard() { - setlocale(LC_COLLATE, __locale_collate); - setlocale(LC_CTYPE, __locale_ctype); - setlocale(LC_MONETARY, __locale_monetary); - setlocale(LC_NUMERIC, __locale_numeric); - setlocale(LC_TIME, __locale_time); - _configthreadlocale(__status); + // The CRT documentation doesn't explicitly say, but setlocale() does the + // right thing when given a semicolon-separated list of locale settings + // for the different categories in the same format as returned by + // setlocale(LC_ALL, nullptr). + if (__locale_all != nullptr) { + __setlocale(__locale_all); + free(__locale_all); + } + _configthreadlocale(__status); + } + static const char* __setlocale(const char* __locale) { + const char* __new_locale = setlocale(LC_ALL, __locale); + if (__new_locale == nullptr) + __throw_bad_alloc(); + return __new_locale; } int __status; - char* __locale_collate; - char* __locale_ctype; - char* __locale_monetary; - char* __locale_numeric; - char* __locale_time; + char* __locale_all = nullptr; }; #endif