Warning: This file is not a C or C++ file. It does not have highlighting.
1 | // -*- C++ -*- |
---|---|
2 | //===----------------------------------------------------------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | #ifndef _LIBCPP___FORMAT_FORMATTER_TUPLE_H |
11 | #define _LIBCPP___FORMAT_FORMATTER_TUPLE_H |
12 | |
13 | #include <__algorithm/ranges_copy.h> |
14 | #include <__chrono/statically_widen.h> |
15 | #include <__config> |
16 | #include <__format/buffer.h> |
17 | #include <__format/concepts.h> |
18 | #include <__format/format_context.h> |
19 | #include <__format/format_error.h> |
20 | #include <__format/format_parse_context.h> |
21 | #include <__format/formatter.h> |
22 | #include <__format/formatter_output.h> |
23 | #include <__format/parser_std_format_spec.h> |
24 | #include <__type_traits/remove_cvref.h> |
25 | #include <__utility/integer_sequence.h> |
26 | #include <__utility/pair.h> |
27 | #include <string_view> |
28 | #include <tuple> |
29 | |
30 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
31 | # pragma GCC system_header |
32 | #endif |
33 | |
34 | _LIBCPP_BEGIN_NAMESPACE_STD |
35 | |
36 | #if _LIBCPP_STD_VER >= 23 |
37 | |
38 | template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args> |
39 | struct __formatter_tuple { |
40 | _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { |
41 | __separator_ = __separator; |
42 | } |
43 | _LIBCPP_HIDE_FROM_ABI constexpr void |
44 | set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { |
45 | __opening_bracket_ = __opening_bracket; |
46 | __closing_bracket_ = __closing_bracket; |
47 | } |
48 | |
49 | template <class _ParseContext> |
50 | _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { |
51 | auto __begin = __parser_.__parse(__ctx, __format_spec::__fields_tuple); |
52 | |
53 | auto __end = __ctx.end(); |
54 | // Note 'n' is part of the type here |
55 | if (__parser_.__clear_brackets_) |
56 | set_brackets({}, {}); |
57 | else if (__begin != __end && *__begin == _CharT('m')) { |
58 | if constexpr (sizeof...(_Args) == 2) { |
59 | set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); |
60 | set_brackets({}, {}); |
61 | ++__begin; |
62 | } else |
63 | std::__throw_format_error("Type m requires a pair or a tuple with two elements"); |
64 | } |
65 | |
66 | if (__begin != __end && *__begin != _CharT('}')) |
67 | std::__throw_format_error("The format specifier should consume the input or end with a '}'"); |
68 | |
69 | __ctx.advance_to(__begin); |
70 | |
71 | // [format.tuple]/7 |
72 | // ... For each element e in underlying_, if e.set_debug_format() |
73 | // is a valid expression, calls e.set_debug_format(). |
74 | std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { |
75 | auto& __formatter = std::get<_Index>(__underlying_); |
76 | __formatter.parse(__ctx); |
77 | // Unlike the range_formatter we don't guard against evil parsers. Since |
78 | // this format-spec never has a format-spec for the underlying type |
79 | // adding the test would give additional overhead. |
80 | std::__set_debug_format(__formatter); |
81 | }); |
82 | |
83 | return __begin; |
84 | } |
85 | |
86 | template <class _FormatContext> |
87 | typename _FormatContext::iterator _LIBCPP_HIDE_FROM_ABI |
88 | format(conditional_t<(formattable<const _Args, _CharT> && ...), const _Tuple&, _Tuple&> __tuple, |
89 | _FormatContext& __ctx) const { |
90 | __format_spec::__parsed_specifications<_CharT> __specs = __parser_.__get_parsed_std_specifications(__ctx); |
91 | |
92 | if (!__specs.__has_width()) |
93 | return __format_tuple(__tuple, __ctx); |
94 | |
95 | // The size of the buffer needed is: |
96 | // - open bracket characters |
97 | // - close bracket character |
98 | // - n elements where every element may have a different size |
99 | // - (n -1) separators |
100 | // The size of the element is hard to predict, knowing the type helps but |
101 | // it depends on the format-spec. As an initial estimate we guess 6 |
102 | // characters. |
103 | // Typically both brackets are 1 character and the separator is 2 |
104 | // characters. Which means there will be |
105 | // (n - 1) * 2 + 1 + 1 = n * 2 character |
106 | // So estimate 8 times the range size as buffer. |
107 | __format::__retarget_buffer<_CharT> __buffer{8 * tuple_size_v<_Tuple>}; |
108 | basic_format_context<typename __format::__retarget_buffer<_CharT>::__iterator, _CharT> __c{ |
109 | __buffer.__make_output_iterator(), __ctx}; |
110 | |
111 | __format_tuple(__tuple, __c); |
112 | |
113 | return __formatter::__write_string_no_precision(basic_string_view{__buffer.__view()}, __ctx.out(), __specs); |
114 | } |
115 | |
116 | template <class _FormatContext> |
117 | _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator __format_tuple(auto&& __tuple, _FormatContext& __ctx) const { |
118 | __ctx.advance_to(std::ranges::copy(__opening_bracket_, __ctx.out()).out); |
119 | |
120 | std::__for_each_index_sequence(make_index_sequence<sizeof...(_Args)>(), [&]<size_t _Index> { |
121 | if constexpr (_Index) |
122 | __ctx.advance_to(std::ranges::copy(__separator_, __ctx.out()).out); |
123 | __ctx.advance_to(std::get<_Index>(__underlying_).format(std::get<_Index>(__tuple), __ctx)); |
124 | }); |
125 | |
126 | return std::ranges::copy(__closing_bracket_, __ctx.out()).out; |
127 | } |
128 | |
129 | __format_spec::__parser<_CharT> __parser_{.__alignment_ = __format_spec::__alignment::__left}; |
130 | |
131 | private: |
132 | tuple<formatter<remove_cvref_t<_Args>, _CharT>...> __underlying_; |
133 | basic_string_view<_CharT> __separator_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ", "); |
134 | basic_string_view<_CharT> __opening_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, "("); |
135 | basic_string_view<_CharT> __closing_bracket_ = _LIBCPP_STATICALLY_WIDEN(_CharT, ")"); |
136 | }; |
137 | |
138 | template <__fmt_char_type _CharT, formattable<_CharT>... _Args> |
139 | struct formatter<pair<_Args...>, _CharT> : public __formatter_tuple<_CharT, pair<_Args...>, _Args...> {}; |
140 | |
141 | template <__fmt_char_type _CharT, formattable<_CharT>... _Args> |
142 | struct formatter<tuple<_Args...>, _CharT> : public __formatter_tuple<_CharT, tuple<_Args...>, _Args...> {}; |
143 | |
144 | #endif // _LIBCPP_STD_VER >= 23 |
145 | |
146 | _LIBCPP_END_NAMESPACE_STD |
147 | |
148 | #endif // _LIBCPP___FORMAT_FORMATTER_TUPLE_H |
149 |
Warning: This file is not a C or C++ file. It does not have highlighting.