This patch implement formatter for vector<bool>::reference which is part of P2286R8.
To indicate partial support we define __glibcxx_format_ranges macro value 1, without defining __cpp_lib_format_ranges. To avoid including the whole content of the <format> header, we introduce new bits/formatfwd.h forward declares classes required for newly introduce formatter. The signatures of the user-facing parse and format method of the provided formatters deviate from the standard by constraining types of params: * _Bit_reference instead T satisfying is-vector-bool-reference<T> * _CharT is constrained __formatter::__char * basic_format_parse_context<_CharT> for parse argument * basic_format_context<_Out, _CharT> for format second argument The standard specifies last three of above as unconstrained types, which leads to formattable<vector<bool>::reference, char32_t> (and any other type as char) being true. PR libstdc++/109162 libstdc++-v3/ChangeLog: * include/Makefile.am: Add bits/formatfwd.h. * include/Makefile.in: Add bits/formatfwd.h. * include/bits/version.def: Define __glibcxx_format_ranges without corresponding std name. * include/bits/version.h: Regenerate. * include/std/format (basic_format_context, __format::__char): Move declartions to bits/formatfwd.h. (formatter<_Tp, _CharT>): Remove default argument for _CharT parameter, now specified in forward declaration in bits/formatfwd.h. * include/std/vector (formatter<_Bit_reference, _CharT>: Define. * include/bits/formatfwd.h: New file with forward declartions for bits of std/format. * testsuite/23_containers/vector/bool/format.cc: New test. --- Testing for x86_64-linux, format tests passed. OK for trunk if all test passes? I think I could land this first to bring __glibcxx_format_ranges macro. libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/formatfwd.h | 68 +++++++++++++++++++ libstdc++-v3/include/bits/version.def | 18 ++--- libstdc++-v3/include/bits/version.h | 10 +++ libstdc++-v3/include/std/format | 14 +--- libstdc++-v3/include/std/vector | 30 ++++++++ .../23_containers/vector/bool/format.cc | 67 ++++++++++++++++++ 8 files changed, 188 insertions(+), 21 deletions(-) create mode 100644 libstdc++-v3/include/bits/formatfwd.h create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/format.cc diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 4dc771a540c..537774c2668 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -195,6 +195,7 @@ bits_headers = \ ${bits_srcdir}/cow_string.h \ ${bits_srcdir}/deque.tcc \ ${bits_srcdir}/erase_if.h \ + ${bits_srcdir}/formatfwd.h \ ${bits_srcdir}/forward_list.h \ ${bits_srcdir}/forward_list.tcc \ ${bits_srcdir}/fs_dir.h \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 0e3d09b3a75..7b96b2207f8 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -548,6 +548,7 @@ bits_freestanding = \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/cow_string.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/deque.tcc \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/erase_if.h \ +@GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/formatfwd.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/forward_list.h \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/forward_list.tcc \ @GLIBCXX_HOSTED_TRUE@ ${bits_srcdir}/fs_dir.h \ diff --git a/libstdc++-v3/include/bits/formatfwd.h b/libstdc++-v3/include/bits/formatfwd.h new file mode 100644 index 00000000000..5450ad1297f --- /dev/null +++ b/libstdc++-v3/include/bits/formatfwd.h @@ -0,0 +1,68 @@ +// <format> Formatting -*- C++ -*- + +// Copyright The GNU Toolchain Authors. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file include/format + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_FORMAT_FWD_H +#define _GLIBCXX_FORMAT_FWD_H 1 + +#ifdef _GLIBCXX_SYSHDR +#pragma GCC system_header +#endif +#ifdef __glibcxx_format // C++ >= 20 && HOSTED + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // [format.context], class template basic_format_context + template<typename _Out, typename _CharT> class basic_format_context; + + // [format.parse.ctx], class template basic_format_parse_context + template<typename _CharT> class basic_format_parse_context; + + // [format.formatter], formatter + template<typename _Tp, typename _CharT = char> struct formatter; + +namespace __format +{ +#ifdef _GLIBCXX_USE_WCHAR_T + template<typename _CharT> + concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>; +#else + template<typename _CharT> + concept __char = same_as<_CharT, char>; +#endif + + template<__char _CharT> + struct __formatter_int; +} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // __glibcxx_format +#pragma GCC diagnostic pop +#endif // _GLIBCXX_FORMAT_FWD_H diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index 1468c0491b7..d7621431762 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1404,18 +1404,18 @@ ftms = { }; }; -// ftms = { - // name = format_ranges; +ftms = { + name = format_ranges; // 202207 P2286R8 Formatting Ranges // 202207 P2585R1 Improving default container formatting // LWG3750 Too many papers bump __cpp_lib_format - // TODO: #define __cpp_lib_format_ranges 202207L - // values = { - // v = 202207; - // cxxmin = 23; - // hosted = yes; - // }; -// }; + stdname = __glibcxx_format_ranges_part; // TODO remove + values = { + v = 1; // TODO 202207 + cxxmin = 23; + hosted = yes; + }; +}; ftms = { name = freestanding_algorithm; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index f7c9849893d..f51bf38418d 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -1555,6 +1555,16 @@ #endif /* !defined(__cpp_lib_expected) && defined(__glibcxx_want_expected) */ #undef __glibcxx_want_expected +#if !defined(__cpp_lib_format_ranges) +# if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED +# define __glibcxx_format_ranges 1L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_format_ranges) +# define __glibcxx_format_ranges_part 1L +# endif +# endif +#endif /* !defined(__cpp_lib_format_ranges) && defined(__glibcxx_want_format_ranges) */ +#undef __glibcxx_want_format_ranges + #if !defined(__cpp_lib_freestanding_algorithm) # if (__cplusplus >= 202100L) # define __glibcxx_freestanding_algorithm 202311L diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 9ef719edcf0..01a53143d1c 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -52,6 +52,7 @@ #include <string_view> #include <string> #include <bits/monostate.h> +#include <bits/formatfwd.h> #include <bits/ranges_base.h> // input_range, range_reference_t #include <bits/ranges_util.h> // subrange #include <bits/ranges_algobase.h> // ranges::copy @@ -73,9 +74,6 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - // [format.context], class template basic_format_context - template<typename _Out, typename _CharT> class basic_format_context; - // [format.fmt.string], class template basic_format_string template<typename _CharT, typename... _Args> struct basic_format_string; @@ -178,7 +176,7 @@ namespace __format // [format.formatter], formatter /// The primary template of std::formatter is disabled. - template<typename _Tp, typename _CharT = char> + template<typename _Tp, typename _CharT> struct formatter { formatter() = delete; // No std::formatter specialization for this type. @@ -923,14 +921,6 @@ namespace __format bool _M_hasval = false; }; -#ifdef _GLIBCXX_USE_WCHAR_T - template<typename _CharT> - concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>; -#else - template<typename _CharT> - concept __char = same_as<_CharT, char>; -#endif - template<__char _CharT> struct __formatter_str { diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 0f043340fe5..e21f5522cd8 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -157,4 +157,34 @@ _GLIBCXX_END_NAMESPACE_VERSION } // namespace std #endif // __cpp_lib_erase_if +#ifdef __glibcxx_format_ranges // C++ >= 20 && HOSTED +#include <bits/formatfwd.h> + +namespace std _GLIBCXX_VISIBILITY(default) +{ + // Standard does not constrain accepted _CharT and declares it as formatter + // of Tp that statisfies is-vector-bool-reference<T>, + template<__format::__char _CharT> + struct formatter<_Bit_reference, _CharT> { + public: + // Standard declares this as template accepting unconstrained + // ParseContext type. + constexpr typename basic_format_parse_context<_CharT>::iterator + parse(basic_format_parse_context<_CharT>& __pc) + { return _M_f.template _M_parse<bool>(__pc); } + + // Standard declares this as template accepting unconstrained + // FormatContext type. + template<typename _Out> + typename basic_format_context<_Out, _CharT>::iterator + format(const _Bit_reference& __u, + basic_format_context<_Out, _CharT>& __fc) const + { return _M_f.format(static_cast<bool>(__u), __fc); } + + private: + __format::__formatter_int<_CharT> _M_f; + }; +} // namespace std +#endif // __glibcxx_format_ranges + #endif /* _GLIBCXX_VECTOR */ diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc new file mode 100644 index 00000000000..1935d06ff88 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/format.cc @@ -0,0 +1,67 @@ +// { dg-do run { target c++23 } } +// { dg-timeout-factor 2 } + +#include <format> +#include <vector> +#include <chrono> // For _Widen +#include <testsuite_hooks.h> + +static_assert(!std::formattable<std::vector<bool>::reference, int>); +static_assert(!std::formattable<std::vector<bool>::reference, char32_t>); + +template<typename... Args> +bool +is_format_string_for(const char* str, Args&&... args) +{ + try { + (void) std::vformat(str, std::make_format_args(args...)); + return true; + } catch (const std::format_error&) { + return false; + } +} + +#define WIDEN_(C, S) ::std::chrono::__detail::_Widen<C>(S, L##S) +#define WIDEN(S) WIDEN_(_CharT, S) + +void +test_format_string() +{ + std::vector<bool> v(1, true); + VERIFY( !is_format_string_for("{:?}", v[0]) ); + VERIFY( !is_format_string_for("{:P}", v[0]) ); + + // width needs to integer type + VERIFY( !is_format_string_for("{:{}}", v[0], 1.0f) ); +} + +template<typename _CharT> +void +test_output() +{ + std::basic_string<_CharT> res; + size_t size = 0; + std::vector<bool> v{true, false}; + + res = std::format(WIDEN("{}"), v[0]); + VERIFY( res == WIDEN("true") ); + + res = std::format(WIDEN("{:s}"), v[1]); + VERIFY( res == WIDEN("false") ); + + res = std::format(WIDEN("{:d} {:#B} {:#o} {:#x}"), v[0], v[1], v[0], v[1]); + VERIFY( res == WIDEN("1 0B0 01 0x0") ); + + res = std::format(WIDEN("{:{}}"), v[0], 6); + VERIFY( res == WIDEN("true ") ); + + res = std::format(WIDEN("{:=^#7X}"), v[1]); + VERIFY( res == WIDEN("==0X0==") ); +} + +int main() +{ + test_format_string(); + test_output<char>(); + test_output<wchar_t>(); +} -- 2.48.1