xref: /llvm-project/libcxx/test/support/format.functions.common.h (revision 49d4fee9940f5e1273cc0ae30da82df9c1437706)
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
5 //
6 //===----------------------------------------------------------------------===//
7 
8 #ifndef TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
9 #define TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
10 
11 // Contains the common part of the formatter tests for different papers.
12 
13 #include <format>
14 
15 #include "make_string.h"
16 
17 #define STR(S) MAKE_STRING(CharT, S)
18 #define SV(S) MAKE_STRING_VIEW(CharT, S)
19 #define CSTR(S) MAKE_CSTRING(CharT, S)
20 
21 template <class T>
22 struct context {};
23 
24 template <>
25 struct context<char> {
26   using type = std::format_context;
27 };
28 
29 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
30 template <>
31 struct context<wchar_t> {
32   using type = std::wformat_context;
33 };
34 #endif
35 
36 template <class T>
37 using context_t = typename context<T>::type;
38 
39 // A user-defined type used to test the handle formatter.
40 enum class status : uint16_t { foo = 0xAAAA, bar = 0x5555, foobar = 0xAA55 };
41 
42 // The formatter for a user-defined type used to test the handle formatter.
43 template <class CharT>
44 struct std::formatter<status, CharT> {
45   int type = 0;
46 
47   constexpr auto parse(basic_format_parse_context<CharT>& parse_ctx) -> decltype(parse_ctx.begin()) {
48     auto begin = parse_ctx.begin();
49     auto end = parse_ctx.end();
50     if (begin == end)
51       return begin;
52 
53     switch (*begin) {
54     case CharT('x'):
55       break;
56     case CharT('X'):
57       type = 1;
58       break;
59     case CharT('s'):
60       type = 2;
61       break;
62     case CharT('}'):
63       return begin;
64     default:
65       throw_format_error("The format-spec type has a type not supported for a status argument");
66     }
67 
68     ++begin;
69     if (begin != end && *begin != CharT('}'))
70       throw_format_error("The format-spec should consume the input or end with a '}'");
71 
72     return begin;
73   }
74 
75   template <class Out>
76   auto format(status s, basic_format_context<Out, CharT>& ctx) const -> decltype(ctx.out()) {
77     const char* names[] = {"foo", "bar", "foobar"};
78     char buffer[7];
79     const char* begin = names[0];
80     const char* end = names[0];
81     switch (type) {
82     case 0:
83       begin = buffer;
84       buffer[0] = '0';
85       buffer[1] = 'x';
86       end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
87       buffer[6] = '\0';
88       break;
89 
90     case 1:
91       begin = buffer;
92       buffer[0] = '0';
93       buffer[1] = 'X';
94       end = std::to_chars(&buffer[2], std::end(buffer), static_cast<uint16_t>(s), 16).ptr;
95       std::transform(static_cast<const char*>(&buffer[2]), end, &buffer[2], [](char c) {
96         return static_cast<char>(std::toupper(c)); });
97       buffer[6] = '\0';
98       break;
99 
100     case 2:
101       switch (s) {
102       case status::foo:
103         begin = names[0];
104         break;
105       case status::bar:
106         begin = names[1];
107         break;
108       case status::foobar:
109         begin = names[2];
110         break;
111       }
112       end = begin + strlen(begin);
113       break;
114     }
115 
116     return std::copy(begin, end, ctx.out());
117   }
118 
119 private:
120   void throw_format_error(const char* s) {
121 #ifndef TEST_HAS_NO_EXCEPTIONS
122     throw std::format_error(s);
123 #else
124     (void)s;
125     std::abort();
126 #endif
127   }
128 };
129 
130 #endif // TEST_SUPPORT_FORMAT_FUNCTIONS_COMMON_H
131