[libcxx-commits] [libcxx] 61a8d42 - [libc++] Optimize std::swap of locales (#209760)

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 4 05:08:33 PDT 2026


Author: Nikolas Klauser
Date: 2026-08-04T14:08:28+02:00
New Revision: 61a8d42409f596def8befa1350f79609de08027c

URL: https://github.com/llvm/llvm-project/commit/61a8d42409f596def8befa1350f79609de08027c
DIFF: https://github.com/llvm/llvm-project/commit/61a8d42409f596def8befa1350f79609de08027c.diff

LOG: [libc++] Optimize std::swap of locales (#209760)

Currently we copy construct `locale`s whenever we swap, which is quite
expensive for locales since that does atomic increments and decrements.
We can just swap the pointers instead.

Added: 
    libcxx/test/benchmarks/text/localization/ctype.bench.cpp
    libcxx/test/benchmarks/text/localization/locale.bench.cpp
    libcxx/test/benchmarks/text/localization/num_get.bench.cpp
    libcxx/test/benchmarks/text/localization/num_put.bench.cpp
    libcxx/test/std/localization/locales/locale/locale.nonmembers/swap.pass.cpp

Modified: 
    libcxx/include/__locale
    libcxx/modules/std/locale.inc

Removed: 
    libcxx/test/benchmarks/locale/ctype.bench.cpp
    libcxx/test/benchmarks/locale/num_get.bench.cpp
    libcxx/test/benchmarks/locale/num_put.bench.cpp


################################################################################
diff  --git a/libcxx/include/__locale b/libcxx/include/__locale
index d5dafc6c65f30..3b7ed38dc46f9 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -146,8 +146,14 @@ private:
   friend bool has_facet(const locale&) _NOEXCEPT;
   template <class _Facet>
   friend const _Facet& use_facet(const locale&);
+
+  _LIBCPP_HIDE_FROM_ABI friend void swap(locale&, locale&) _NOEXCEPT;
 };
 
+_LIBCPP_HIDE_FROM_ABI inline void swap(locale& __lhs, locale& __rhs) _NOEXCEPT {
+  std::swap(__lhs.__locale_, __rhs.__locale_);
+}
+
 class _LIBCPP_EXPORTED_FROM_ABI locale::facet : public __shared_count {
 protected:
   _LIBCPP_HIDE_FROM_ABI explicit facet(size_t __refs = 0) : __shared_count(static_cast<long>(__refs) - 1) {}

diff  --git a/libcxx/modules/std/locale.inc b/libcxx/modules/std/locale.inc
index cdc7441ece52e..44e853651e81c 100644
--- a/libcxx/modules/std/locale.inc
+++ b/libcxx/modules/std/locale.inc
@@ -12,6 +12,7 @@ export namespace std {
   // [locale], locale
   using std::has_facet;
   using std::locale;
+  using std::swap;
   using std::use_facet;
 
   // [locale.convenience], convenience interfaces

diff  --git a/libcxx/test/benchmarks/locale/ctype.bench.cpp b/libcxx/test/benchmarks/text/localization/ctype.bench.cpp
similarity index 100%
rename from libcxx/test/benchmarks/locale/ctype.bench.cpp
rename to libcxx/test/benchmarks/text/localization/ctype.bench.cpp

diff  --git a/libcxx/test/benchmarks/text/localization/locale.bench.cpp b/libcxx/test/benchmarks/text/localization/locale.bench.cpp
new file mode 100644
index 0000000000000..60bc541bc053f
--- /dev/null
+++ b/libcxx/test/benchmarks/text/localization/locale.bench.cpp
@@ -0,0 +1,28 @@
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03
+
+#include <ios>
+#include <locale>
+
+#include <benchmark/benchmark.h>
+
+static void BM_num_get(benchmark::State& state) {
+  std::locale loc1, loc2;
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(loc1);
+    benchmark::DoNotOptimize(loc2);
+    std::swap(loc1, loc2);
+  }
+}
+BENCHMARK(BM_num_get)->Name("std::swap(std::locale&, std::locale&)");
+
+BENCHMARK_MAIN();

diff  --git a/libcxx/test/benchmarks/locale/num_get.bench.cpp b/libcxx/test/benchmarks/text/localization/num_get.bench.cpp
similarity index 100%
rename from libcxx/test/benchmarks/locale/num_get.bench.cpp
rename to libcxx/test/benchmarks/text/localization/num_get.bench.cpp

diff  --git a/libcxx/test/benchmarks/locale/num_put.bench.cpp b/libcxx/test/benchmarks/text/localization/num_put.bench.cpp
similarity index 100%
rename from libcxx/test/benchmarks/locale/num_put.bench.cpp
rename to libcxx/test/benchmarks/text/localization/num_put.bench.cpp

diff  --git a/libcxx/test/std/localization/locales/locale/locale.nonmembers/swap.pass.cpp b/libcxx/test/std/localization/locales/locale/locale.nonmembers/swap.pass.cpp
new file mode 100644
index 0000000000000..3578334b1667b
--- /dev/null
+++ b/libcxx/test/std/localization/locales/locale/locale.nonmembers/swap.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: locale.en_US.UTF-8
+
+// UNSUPPORTED: c++03
+
+// <locale>
+
+// void swap(locale &, locale &) noexcept
+
+#include <cassert>
+#include <locale>
+
+#include "platform_support.h"
+
+int main(int, char**) {
+  std::locale loc1 = std::locale::classic();
+  std::locale loc2(LOCALE_en_US_UTF_8);
+
+  assert(loc1 != loc2);
+
+  std::locale expected_lhs = loc2;
+  std::locale expected_rhs = loc1;
+
+  static_assert(noexcept(swap(loc1, loc2)), "");
+
+  swap(loc1, loc2);
+  assert(loc1 == expected_lhs);
+  assert(loc2 == expected_rhs);
+
+  return 0;
+}


        


More information about the libcxx-commits mailing list