[libcxx-commits] [libcxx] r357104 - Fix and speedup __libcpp_locale_guard on Windows

Thomas Anderson via libcxx-commits libcxx-commits at lists.llvm.org
Wed Mar 27 11:09:30 PDT 2019


Author: thomasanderson
Date: Wed Mar 27 11:09:30 2019
New Revision: 357104

URL: http://llvm.org/viewvc/llvm-project?rev=357104&view=rev
Log:
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

Modified:
    libcxx/trunk/include/__locale

Modified: libcxx/trunk/include/__locale
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__locale?rev=357104&r1=357103&r2=357104&view=diff
==============================================================================
--- libcxx/trunk/include/__locale (original)
+++ libcxx/trunk/include/__locale Wed Mar 27 11:09:30 2019
@@ -19,6 +19,7 @@
 #include <cctype>
 #include <locale.h>
 #if defined(_LIBCPP_MSVCRT_LIKE)
+# include <cstring>
 # include <support/win32/locale_win32.h>
 #elif defined(_AIX)
 # include <support/ibm/xlocale.h>
@@ -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
 




More information about the libcxx-commits mailing list