1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //===----------------------------------------------------------------------===//
8 #ifndef TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
9 #define TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
11 // Contains the common part of the formatter tests for different papers.
21 #include <string_view>
24 #include "make_string.h"
26 #define STR(S) MAKE_STRING(CharT, S)
27 #define SV(S) MAKE_STRING_VIEW(CharT, S)
28 #define CSTR(S) MAKE_CSTRING(CharT, S)
34 struct context
<char> {
35 using type
= std::format_context
;
38 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
40 struct context
<wchar_t> {
41 using type
= std::wformat_context
;
46 using context_t
= typename context
<T
>::type
;
48 // A user-defined type used to test the handle formatter.
49 enum class status
: std::uint16_t { foo
= 0xAAAA, bar
= 0x5555, foobar
= 0xAA55 };
51 // The formatter for a user-defined type used to test the handle formatter.
52 template <class CharT
>
53 struct std::formatter
<status
, CharT
> {
54 // During the 2023 Issaquah meeting LEWG made it clear a formatter is
55 // required to call its parse function. LWG3892 Adds the wording for that
56 // requirement. Therefore this formatter is initialized in an invalid state.
57 // A call to parse sets it in a valid state and a call to format validates
61 constexpr auto parse(basic_format_parse_context
<CharT
>& parse_ctx
) -> decltype(parse_ctx
.begin()) {
62 auto begin
= parse_ctx
.begin();
63 auto end
= parse_ctx
.end();
80 throw_format_error("The type option contains an invalid value for a status formatting argument");
84 if (begin
!= end
&& *begin
!= CharT('}'))
85 throw_format_error("The format specifier should consume the input or end with a '}'");
91 auto format(status s
, basic_format_context
<Out
, CharT
>& ctx
) const -> decltype(ctx
.out()) {
92 const char* names
[] = {"foo", "bar", "foobar"};
94 const char* begin
= names
[0];
95 const char* end
= names
[0];
98 throw_format_error("The formatter's parse function has not been called.");
104 end
= std::to_chars(&buffer
[2], std::end(buffer
), static_cast<std::uint16_t>(s
), 16).ptr
;
112 end
= std::to_chars(&buffer
[2], std::end(buffer
), static_cast<std::uint16_t>(s
), 16).ptr
;
113 std::transform(static_cast<const char*>(&buffer
[2]), end
, &buffer
[2], [](char c
) {
114 return static_cast<char>(std::toupper(c
)); });
130 end
= begin
+ strlen(begin
);
134 return std::copy(begin
, end
, ctx
.out());
138 [[noreturn
]] void throw_format_error([[maybe_unused
]] const char* s
) const {
139 #ifndef TEST_HAS_NO_EXCEPTIONS
140 throw std::format_error(s
);
147 struct parse_call_validator
{
148 struct parse_function_not_called
{};
150 friend constexpr auto operator<=>(const parse_call_validator
& lhs
, const parse_call_validator
& rhs
) {
151 return &lhs
<=> &rhs
;
155 // The formatter for a user-defined type used to test the handle formatter.
157 // Like std::formatter<status, CharT> this formatter validates that parse is
158 // called. This formatter is intended to be used when the formatter's parse is
159 // called directly and not with format. In that case the format-spec does not
160 // require a terminating }. The tests must be written in a fashion where this
161 // formatter is always called with an empty format-spec. This requirement
162 // allows testing of certain code paths that are never reached by using a
163 // well-formed format-string in the format functions.
164 template <class CharT
>
165 struct std::formatter
<parse_call_validator
, CharT
> {
166 bool parse_called
{false};
168 constexpr auto parse(basic_format_parse_context
<CharT
>& parse_ctx
) -> decltype(parse_ctx
.begin()) {
169 auto begin
= parse_ctx
.begin();
170 auto end
= parse_ctx
.end();
171 assert(begin
== end
);
176 auto format(parse_call_validator
, auto& ctx
) const -> decltype(ctx
.out()) {
178 throw_error
<parse_call_validator::parse_function_not_called
>();
184 [[noreturn
]] void throw_error() const {
185 #ifndef TEST_HAS_NO_EXCEPTIONS
193 // Creates format string for the invalid types.
195 // valid contains a list of types that are valid.
196 // - The type ?s is the only type requiring 2 characters, use S for that type.
197 // - Whether n is a type or not depends on the context, is is always used.
199 // The return value is a collection of basic_strings, instead of
200 // basic_string_views since the values are temporaries.
202 template <class CharT
, std::size_t N
>
203 std::basic_string
<CharT
> get_colons() {
204 static std::basic_string
<CharT
> result(N
, CharT(':'));
208 constexpr std::string_view
get_format_types() {
209 return "aAbBcdeEfFgGopPsxX"
210 #if TEST_STD_VER > 20
216 template <class CharT
, /*format_types types,*/ size_t N
>
217 std::vector
<std::basic_string
<CharT
>> fmt_invalid_types(std::string_view valid
) {
218 // std::ranges::to is not available in C++20.
219 std::vector
<std::basic_string
<CharT
>> result
;
221 get_format_types() | std::views::filter([&](char type
) { return valid
.find(type
) == std::string_view::npos
; }) |
222 std::views::transform([&](char type
) { return std::format(SV("{{{}{}}}"), get_colons
<CharT
, N
>(), type
); }),
223 std::back_inserter(result
));
227 } // namespace detail
229 // Creates format string for the invalid types.
231 // valid contains a list of types that are valid.
233 // The return value is a collection of basic_strings, instead of
234 // basic_string_views since the values are temporaries.
235 template <class CharT
>
236 std::vector
<std::basic_string
<CharT
>> fmt_invalid_types(std::string_view valid
) {
237 return detail::fmt_invalid_types
<CharT
, 1>(valid
);
240 // Like fmt_invalid_types but when the format spec is for an underlying formatter.
241 template <class CharT
>
242 std::vector
<std::basic_string
<CharT
>> fmt_invalid_nested_types(std::string_view valid
) {
243 return detail::fmt_invalid_types
<CharT
, 2>(valid
);
246 #endif // TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H