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