diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h index e2f418f936ee10e..39c2670dd84317c 100644 --- a/libcxx/include/__format/formatter.h +++ b/libcxx/include/__format/formatter.h @@ -39,6 +39,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(); }) diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h index 17dc69541e8fe1b..63aa815efbe9b3a 100644 --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -69,7 +69,11 @@ struct _LIBCPP_TEMPLATE_VIS formatter { __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 d33e84368a7650d..abfd65a42829894 100644 --- a/libcxx/include/__format/formatter_char.h +++ b/libcxx/include/__format/formatter_char.h @@ -83,9 +83,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 fa42ba203b0b5e2..334755f4e8143b3 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 41400f00478eb47..2c2e7995053671e 100644 --- a/libcxx/include/__format/formatter_integer.h +++ b/libcxx/include/__format/formatter_integer.h @@ -88,7 +88,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 6941343efd91f99..e1c062cec6ed2b1 100644 --- a/libcxx/include/__format/formatter_pointer.h +++ b/libcxx/include/__format/formatter_pointer.h @@ -65,6 +65,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 347439fc8dff132..dee2b3ad073a516 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -143,7 +143,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 a88b3ef8528e2d1..449e6f0bf3fb63d 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 743a43811005a4b..09aa03ad73e3885 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 000000000000000..fb078fdc7559eb7 --- /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(); +}