-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][format] Implements P3107R5 in <format>. #86713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesThis 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
Patch is 21.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86713.diff 9 Files Affected:
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/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_...
[truncated]
|
6269449
to
8c306d1
Compare
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``
8c306d1
to
ac458a6
Compare
ldionne
approved these changes
Jul 30, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This adds the new std::enable_nonlocking_formatter_optimization trait in . This trait will be used in std::print to implement the performance benefits.
Implements parts of
std::print