From ac458a68865883b6f96bb68201ee6e627a8c0a54 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Mon, 25 Mar 2024 20:26:33 +0100 Subject: [libc++][format] Implements P3107R5 in . 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 - 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 +- libcxx/include/__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 + ...locking_formatter_optimization.compile.pass.cpp | 235 +++++++++++++++++++++ 10 files changed, 337 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 47e3578..0316354 100644 --- a/libcxx/include/__format/formatter.h +++ b/libcxx/include/__format/formatter.h @@ -41,6 +41,9 @@ struct _LIBCPP_TEMPLATE_VIS formatter { # if _LIBCPP_STD_VER >= 23 template +constexpr bool enable_nonlocking_formatter_optimization = false; + +template _LIBCPP_HIDE_FROM_ABI constexpr void __set_debug_format(_Tp& __formatter) { if constexpr (requires { __formatter.set_debug_format(); }) __formatter.set_debug_format(); diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h index 5e3daff7..9d9fcd2 100644 --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -70,7 +70,11 @@ public: __format_spec::__parser<_CharT> __parser_; }; -#endif //_LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 23 +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 3358d42..aa9c565 100644 --- a/libcxx/include/__format/formatter_char.h +++ b/libcxx/include/__format/formatter_char.h @@ -84,9 +84,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_char struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_char {}; - # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS +# if _LIBCPP_STD_VER >= 23 +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 1d94cc3..11aafab 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 : public __formatter_float template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_floating_point<_CharT> {}; +# if _LIBCPP_STD_VER >= 23 +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 d57082b..d636172 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 = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 3373996..26788b9 100644 --- a/libcxx/include/__format/formatter_pointer.h +++ b/libcxx/include/__format/formatter_pointer.h @@ -66,6 +66,14 @@ struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_pointe template <__fmt_char_type _CharT> struct _LIBCPP_TEMPLATE_VIS formatter : public __formatter_pointer<_CharT> {}; +# if _LIBCPP_STD_VER >= 23 +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = 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 d1ccfb9..7da5d63 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -144,7 +144,32 @@ struct _LIBCPP_TEMPLATE_VIS formatter, _CharT } }; -#endif //_LIBCPP_STD_VER >= 20 +# if _LIBCPP_STD_VER >= 23 +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization> = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization> = true; + +# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template <> +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization> = true; +template +inline constexpr bool enable_nonlocking_formatter_optimization> = 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 f1e87de..e037880a 100644 --- a/libcxx/include/format +++ b/libcxx/include/format @@ -126,6 +126,9 @@ namespace std { // [format.formatter], formatter template struct formatter; + template + constexpr bool enable_nonlocking_formatter_optimization = false; // since C++23 + // [format.parse.ctx], class template basic_format_parse_context template class basic_format_parse_context; using format_parse_context = basic_format_parse_context; @@ -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 - constexpr unspecified format_kind = unspecified; // since C++23 + constexpr unspecified format_kind = unspecified; // since C++23 template requires same_as> - constexpr range_format format_kind = see below; // since C++23 + constexpr range_format format_kind = see below; // since C++23 // [format.range.formatter], class template range_formatter template requires same_as, T> && formattable - class range_formatter; // since C++23 + class range_formatter; // since C++23 // [format.range.fmtdef], class template range-default-formatter template - 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 arg); // Deprecated in C++26 // [format.arg.store], class template format-arg-store - template struct format-arg-store; // exposition only + template struct format-arg-store; // exposition only template format-arg-store diff --git a/libcxx/modules/std/format.inc b/libcxx/modules/std/format.inc index 743a438..09aa03a 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 0000000..fb078fd --- /dev/null +++ b/libcxx/test/std/utilities/format/format.formatter/format.formatter.locking/enable_nonlocking_formatter_optimization.compile.pass.cpp @@ -0,0 +1,235 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// template +// 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 = true; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "min_allocator.h" + +#ifndef TEST_HAS_NO_LOCALIZATION +# include +#endif +#ifndef TEST_HAS_NO_THREADS +# include +#endif + +// Tests for P0645 Text Formatting +template +void test_P0645() { + static_assert(std::enable_nonlocking_formatter_optimization); + + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + + static_assert(std::enable_nonlocking_formatter_optimization>); + static_assert(std::enable_nonlocking_formatter_optimization>); + + static_assert(std::enable_nonlocking_formatter_optimization); + + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); +#ifndef TEST_HAS_NO_INT128 + static_assert(std::enable_nonlocking_formatter_optimization<__int128_t>); +#endif + + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); +#ifndef TEST_HAS_NO_INT128 + static_assert(std::enable_nonlocking_formatter_optimization<__uint128_t>); +#endif + + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization); +} + +// 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); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + //static_assert(!std::enable_nonlocking_formatter_optimization>); + //static_assert(!std::enable_nonlocking_formatter_optimization>); + //static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + + //static_assert(!std::enable_nonlocking_formatter_optimization); + //static_assert(!std::enable_nonlocking_formatter_optimization); + + //static_assert(!std::enable_nonlocking_formatter_optimization); + +#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); +#endif +} + +template +void test_P2286_vector_bool() { + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(!std::enable_nonlocking_formatter_optimization); + + // The const_reference shall be a bool. + // However libc++ uses a __bit_const_reference when + // _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL is defined. + static_assert(!std::enable_nonlocking_formatter_optimization); + static_assert(std::enable_nonlocking_formatter_optimization == + std::same_as); +} + +// Tests for P2286 Formatting ranges +void test_P2286() { + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + + static_assert(!std::enable_nonlocking_formatter_optimization>); + static_assert(!std::enable_nonlocking_formatter_optimization>); + + test_P2286_vector_bool>(); + test_P2286_vector_bool>>(); + test_P2286_vector_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); + +struct not_formattable_nonlocking_enabled {}; +template <> +inline constexpr bool std::enable_nonlocking_formatter_optimization = true; +static_assert(std::enable_nonlocking_formatter_optimization); + +void test() { + test_P0645(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_P0645(); +#endif + test_P1361(); + test_P1636(); + test_P2286(); +} -- cgit v1.1