[libcxx-commits] [libcxx] [libc++][format] Implements P3107R5 in <format>. (PR #86713)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Tue Mar 26 12:32:04 PDT 2024


https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/86713

>From 626944965aec893e46db468bdf898fbe562912b3 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Mon, 25 Mar 2024 20:26:33 +0100
Subject: [PATCH] [libc++][format] Implements P3107R5 in <format>.

This adds the new std::enable_nonlocking_formatter_optimization trait in
<format>. This trait will be used in std::print to implement the
performance benefits.

Implements parts of
- P3107R5 - Permit an efficient implementation of ``std::print``
---
 libcxx/include/__format/formatter.h           |   3 +
 libcxx/include/__format/formatter_bool.h      |   6 +-
 libcxx/include/__format/formatter_char.h      |  10 +-
 .../__format/formatter_floating_point.h       |   8 +
 libcxx/include/__format/formatter_integer.h   |  33 ++-
 libcxx/include/__format/formatter_pointer.h   |   8 +
 libcxx/include/__format/formatter_string.h    |  27 +-
 libcxx/include/format                         |  15 +-
 libcxx/modules/std/format.inc                 |   2 +
 ...ng_formatter_optimization.compile.pass.cpp | 233 ++++++++++++++++++
 10 files changed, 335 insertions(+), 10 deletions(-)
 create mode 100644 libcxx/test/std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp

diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h
index 47e35789b8175b..0316354ba74a16 100644
--- a/libcxx/include/__format/formatter.h
+++ b/libcxx/include/__format/formatter.h
@@ -40,6 +40,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter {
 
 #  if _LIBCPP_STD_VER >= 23
 
+template <class _Tp>
+constexpr bool enable_nonlocking_formatter_optimization = false;
+
 template <class _Tp>
 _LIBCPP_HIDE_FROM_ABI constexpr void __set_debug_format(_Tp& __formatter) {
   if constexpr (requires { __formatter.set_debug_format(); })
diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h
index 5e3daff7b3dba6..9d9fcd2469ce1f 100644
--- a/libcxx/include/__format/formatter_bool.h
+++ b/libcxx/include/__format/formatter_bool.h
@@ -70,7 +70,11 @@ struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
   __format_spec::__parser<_CharT> __parser_;
 };
 
-#endif //_LIBCPP_STD_VER >= 20
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<bool> = true;
+#  endif //_LIBCPP_STD_VER >= 23
+#endif   //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__format/formatter_char.h b/libcxx/include/__format/formatter_char.h
index 3358d422252f43..aa9c56538efdce 100644
--- a/libcxx/include/__format/formatter_char.h
+++ b/libcxx/include/__format/formatter_char.h
@@ -84,9 +84,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t> : public __formatter_char<w
 
 template <>
 struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t> : public __formatter_char<wchar_t> {};
-
 #  endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
 
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<char> = true;
+#    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<wchar_t> = true;
+#    endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+#  endif   //_LIBCPP_STD_VER >= 23
+
 #endif //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index 1d94cc349c0dd6..11aafab0db1fd9 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -774,6 +774,14 @@ struct _LIBCPP_TEMPLATE_VIS formatter<double, _CharT> : public __formatter_float
 template <__fmt_char_type _CharT>
 struct _LIBCPP_TEMPLATE_VIS formatter<long double, _CharT> : public __formatter_floating_point<_CharT> {};
 
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<float> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<double> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<long double> = true;
+#  endif //_LIBCPP_STD_VER >= 23
 #endif //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__format/formatter_integer.h b/libcxx/include/__format/formatter_integer.h
index d57082b3881baa..d63617233d7631 100644
--- a/libcxx/include/__format/formatter_integer.h
+++ b/libcxx/include/__format/formatter_integer.h
@@ -89,7 +89,38 @@ template <__fmt_char_type _CharT>
 struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT> : public __formatter_integer<_CharT> {};
 #  endif
 
-#endif //_LIBCPP_STD_VER >= 20
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<signed char> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<short> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<int> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<long> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<long long> = true;
+#    ifndef _LIBCPP_HAS_NO_INT128
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<__int128_t> = true;
+#    endif
+
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<unsigned char> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<unsigned short> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<unsigned> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<unsigned long> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<unsigned long long> = true;
+#    ifndef _LIBCPP_HAS_NO_INT128
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<__uint128_t> = true;
+#    endif
+#  endif //_LIBCPP_STD_VER >= 23
+#endif   //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/__format/formatter_pointer.h b/libcxx/include/__format/formatter_pointer.h
index 3373996ec3d5fa..26788b944db136 100644
--- a/libcxx/include/__format/formatter_pointer.h
+++ b/libcxx/include/__format/formatter_pointer.h
@@ -66,6 +66,14 @@ struct _LIBCPP_TEMPLATE_VIS formatter<void*, _CharT> : public __formatter_pointe
 template <__fmt_char_type _CharT>
 struct _LIBCPP_TEMPLATE_VIS formatter<const void*, _CharT> : public __formatter_pointer<_CharT> {};
 
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<nullptr_t> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<void*> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<const void*> = true;
+#  endif //_LIBCPP_STD_VER >= 23
 #endif //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h
index d1ccfb9b5f7dc9..7da5d63d4487c0 100644
--- a/libcxx/include/__format/formatter_string.h
+++ b/libcxx/include/__format/formatter_string.h
@@ -144,7 +144,32 @@ struct _LIBCPP_TEMPLATE_VIS formatter<basic_string_view<_CharT, _Traits>, _CharT
   }
 };
 
-#endif //_LIBCPP_STD_VER >= 20
+#  if _LIBCPP_STD_VER >= 23
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<char*> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<const char*> = true;
+template <size_t _Size>
+inline constexpr bool enable_nonlocking_formatter_optimization<char[_Size]> = true;
+template <class _Traits, class _Allocator>
+inline constexpr bool enable_nonlocking_formatter_optimization<basic_string<char, _Traits, _Allocator>> = true;
+template <class _Traits>
+inline constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<char, _Traits>> = true;
+
+#    ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<wchar_t*> = true;
+template <>
+inline constexpr bool enable_nonlocking_formatter_optimization<const wchar_t*> = true;
+template <size_t _Size>
+inline constexpr bool enable_nonlocking_formatter_optimization<wchar_t[_Size]> = true;
+template <class _Traits, class _Allocator>
+inline constexpr bool enable_nonlocking_formatter_optimization<basic_string<wchar_t, _Traits, _Allocator>> = true;
+template <class _Traits>
+inline constexpr bool enable_nonlocking_formatter_optimization<basic_string_view<wchar_t, _Traits>> = true;
+#    endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+#  endif   //_LIBCPP_STD_VER >= 23
+#endif     //_LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/format b/libcxx/include/format
index 146613464534f7..e6d62fa9b5ad52 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -126,6 +126,9 @@ namespace std {
   // [format.formatter], formatter
   template<class T, class charT = char> struct formatter;
 
+  template<class T>
+  constexpr bool enable_nonlocking_formatter_optimization = false;   // since C++23
+
   // [format.parse.ctx], class template basic_format_parse_context
   template<class charT> class basic_format_parse_context;
   using format_parse_context = basic_format_parse_context<char>;
@@ -133,7 +136,7 @@ namespace std {
 
   // [format.range], formatting of ranges
   // [format.range.fmtkind], variable template format_kind
-  enum class range_format {                                     // since C++23
+  enum class range_format {                                          // since C++23
     disabled,
     map,
     set,
@@ -143,20 +146,20 @@ namespace std {
   };
 
   template<class R>
-    constexpr unspecified format_kind = unspecified;            // since C++23
+    constexpr unspecified format_kind = unspecified;                 // since C++23
 
   template<ranges::input_range R>
       requires same_as<R, remove_cvref_t<R>>
-    constexpr range_format format_kind<R> = see below;          // since C++23
+    constexpr range_format format_kind<R> = see below;               // since C++23
 
   // [format.range.formatter], class template range_formatter
   template<class T, class charT = char>
     requires same_as<remove_cvref_t<T>, T> && formattable<T, charT>
-  class range_formatter;                                        // since C++23
+  class range_formatter;                                             // since C++23
 
   // [format.range.fmtdef], class template range-default-formatter
   template<range_format K, ranges::input_range R, class charT>
-    struct range-default-formatter;                             // exposition only, since C++23
+    struct range-default-formatter;                                  // exposition only, since C++23
 
   // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
   // specializations for maps, sets, and strings
@@ -173,7 +176,7 @@ namespace std {
     see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); // Deprecated in C++26
 
   // [format.arg.store], class template format-arg-store
-  template<class Context, class... Args> struct format-arg-store;      // exposition only
+  template<class Context, class... Args> struct format-arg-store;    // exposition only
 
   template<class Context = format_context, class... Args>
     format-arg-store<Context, Args...>
diff --git a/libcxx/modules/std/format.inc b/libcxx/modules/std/format.inc
index 743a43811005a4..09aa03ad73e388 100644
--- a/libcxx/modules/std/format.inc
+++ b/libcxx/modules/std/format.inc
@@ -46,6 +46,8 @@ export namespace std {
   using std::formatter;
 
 #if _LIBCPP_STD_VER >= 23
+  using std::enable_nonlocking_formatter_optimization;
+
   // [format.formattable], concept formattable
   using std::formattable;
 #endif
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp
new file mode 100644
index 00000000000000..442f1e8528fc90
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp
@@ -0,0 +1,233 @@
+//===----------------------------------------------------------------------===//
+// 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, c++11, c++14, c++17, c++20
+
+// <format>
+
+// template<class T>
+// constexpr bool enable_nonlocking_formatter_optimization = false;
+
+// Remarks: Pursuant to [namespace.std], users may specialize
+// enable_nonlocking_formatter_optimization for cv-unqualified program-defined
+// types. Such specializations shall be usable in constant expressions
+// ([expr.const]) and have type const bool.
+
+// [format.formatter.spec]
+// In addition, for each type T for which a formatter specialization is provided
+// above, each of the headers provides the following specialization:
+//
+// template<>
+// inline constexpr bool enable_nonlocking_formatter_optimization<T> = true;
+
+#include <array>
+#include <bitset>
+#include <bitset>
+#include <chrono>
+#include <complex>
+#include <concepts>
+#include <deque>
+#include <filesystem>
+#include <format>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <queue>
+#include <set>
+#include <span>
+#include <stack>
+#include <system_error>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <valarray>
+#include <variant>
+
+#include "test_macros.h"
+#include "min_allocator.h"
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+#  include <regex>
+#endif
+#ifndef TEST_HAS_NO_THREADS
+#  include <thread>
+#endif
+
+// Tests for P0645 Text Formatting
+template <class CharT>
+void test_P0645() {
+  static_assert(std::enable_nonlocking_formatter_optimization<CharT>);
+
+  static_assert(std::enable_nonlocking_formatter_optimization<CharT*>);
+  static_assert(std::enable_nonlocking_formatter_optimization<const CharT*>);
+  static_assert(std::enable_nonlocking_formatter_optimization<CharT[42]>);
+
+  static_assert(std::enable_nonlocking_formatter_optimization<std::basic_string<CharT>>);
+  static_assert(std::enable_nonlocking_formatter_optimization<std::basic_string_view<CharT>>);
+
+  static_assert(std::enable_nonlocking_formatter_optimization<bool>);
+
+  static_assert(std::enable_nonlocking_formatter_optimization<signed char>);
+  static_assert(std::enable_nonlocking_formatter_optimization<signed short>);
+  static_assert(std::enable_nonlocking_formatter_optimization<signed int>);
+  static_assert(std::enable_nonlocking_formatter_optimization<signed long>);
+  static_assert(std::enable_nonlocking_formatter_optimization<signed long long>);
+#ifndef TEST_HAS_NO_INT128
+  static_assert(std::enable_nonlocking_formatter_optimization<__int128_t>);
+#endif
+
+  static_assert(std::enable_nonlocking_formatter_optimization<unsigned char>);
+  static_assert(std::enable_nonlocking_formatter_optimization<unsigned short>);
+  static_assert(std::enable_nonlocking_formatter_optimization<unsigned int>);
+  static_assert(std::enable_nonlocking_formatter_optimization<unsigned long>);
+  static_assert(std::enable_nonlocking_formatter_optimization<unsigned long long>);
+#ifndef TEST_HAS_NO_INT128
+  static_assert(std::enable_nonlocking_formatter_optimization<__uint128_t>);
+#endif
+
+  static_assert(std::enable_nonlocking_formatter_optimization<float>);
+  static_assert(std::enable_nonlocking_formatter_optimization<double>);
+  static_assert(std::enable_nonlocking_formatter_optimization<long double>);
+
+  static_assert(std::enable_nonlocking_formatter_optimization<std::nullptr_t>);
+  static_assert(std::enable_nonlocking_formatter_optimization<void*>);
+  static_assert(std::enable_nonlocking_formatter_optimization<const void*>);
+}
+
+// Tests for P1361 Integration of chrono with text formatting
+//
+// Some tests are commented out since these types haven't been implemented in
+// chrono yet. After P1361 has been implemented these formatters should be all
+// enabled.
+void test_P1361() {
+// The chrono formatters require localization support.
+// [time.format]/7
+//   If the chrono-specs is omitted, the chrono object is formatted as if by
+//   streaming it to std::ostringstream os with the formatting
+//   locale imbued and copying os.str() through the output iterator of the
+//   context with additional padding and adjustments as specified by the format
+//   specifiers.
+// In libc++ std:::ostringstream requires localization support.
+#ifndef TEST_HAS_NO_LOCALIZATION
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::microseconds>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::sys_time<std::chrono::microseconds>>);
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::utc_time<std::chrono::microseconds>>);
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::tai_time<std::chrono::microseconds>>);
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::gps_time<std::chrono::microseconds>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::file_time<std::chrono::microseconds>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::local_time<std::chrono::microseconds>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::day>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::month>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::weekday>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::weekday_indexed>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::weekday_last>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::month_day>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::month_day_last>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::month_weekday>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::month_weekday_last>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year_month>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year_month_day>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year_month_day_last>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year_month_weekday>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::year_month_weekday_last>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::hh_mm_ss<std::chrono::microseconds>>);
+
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::sys_info>);
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::local_info>);
+
+  //static_assert(!std::enable_nonlocking_formatter_optimization<std::chrono::zoned_time>);
+
+#endif // TEST_HAS_NO_LOCALIZATION
+}
+
+// Tests for P1636 Formatters for library types
+//
+// The paper hasn't been voted in so currently all formatters are disabled.
+// Note the paper has been abandoned, the types are kept since other papers may
+// introduce these formatters.
+void test_P1636() {
+#ifndef TEST_HAS_NO_THREADS
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::thread::id>);
+#endif
+}
+
+template <class Vector>
+void test_P2286_vector_bool() {
+  static_assert(!std::enable_nonlocking_formatter_optimization<Vector>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<typename Vector::reference>);
+
+  // The const_reference shall be a bool.
+  // However libc++ uses a __bit_const_reference<vector> when
+  // _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL is defined.
+  static_assert(!std::enable_nonlocking_formatter_optimization<const Vector&>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<typename Vector::const_reference>);
+}
+
+// Tests for P2286 Formatting ranges
+void test_P2286() {
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::array<int, 42>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::vector<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::deque<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::forward_list<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::list<int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::set<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::map<int, int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::multiset<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::multimap<int, int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::unordered_set<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::unordered_map<int, int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::unordered_multiset<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::unordered_multimap<int, int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::stack<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::queue<int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::priority_queue<int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::span<int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::valarray<int>>);
+
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::pair<int, int>>);
+  static_assert(!std::enable_nonlocking_formatter_optimization<std::tuple<int>>);
+
+  test_P2286_vector_bool<std::vector<bool>>();
+  test_P2286_vector_bool<std::vector<bool, std::allocator<bool>>>();
+  test_P2286_vector_bool<std::vector<bool, min_allocator<bool>>>();
+}
+
+// The trait does not care about whether the type is formattable, obviously the
+// trait for non formattable types are not used.
+struct not_formattable_nonlocking_disabled {};
+static_assert(!std::enable_nonlocking_formatter_optimization<not_formattable_nonlocking_disabled>);
+
+struct not_formattable_nonlocking_enabled {};
+template <>
+inline constexpr bool std::enable_nonlocking_formatter_optimization<not_formattable_nonlocking_enabled> = true;
+static_assert(std::enable_nonlocking_formatter_optimization<not_formattable_nonlocking_enabled>);
+
+void test() {
+  test_P0645<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+  test_P0645<wchar_t>();
+#endif
+  test_P1361();
+  test_P1636();
+  test_P2286();
+}



More information about the libcxx-commits mailing list