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 // UNSUPPORTED: c++03, c++11, c++14, c++17
9 // UNSUPPORTED: libcpp-has-no-incomplete-format
10
11 // <format>
12
13 // basic_format_arg<Context> get(size_t i) const noexcept;
14
15 #include <format>
16 #include <cassert>
17 #include <type_traits>
18
19 #include "test_macros.h"
20 #include "make_string.h"
21
22 template <class Context, class To, class From>
test(From value)23 void test(From value) {
24 auto store = std::make_format_args<Context>(value);
25 const std::basic_format_args<Context> format_args{store};
26
27 std::visit_format_arg(
28 [v = To(value)](auto a) {
29 if constexpr (std::is_same_v<To, decltype(a)>)
30 assert(v == a);
31 else
32 assert(false);
33 },
34 format_args.get(0));
35 }
36
37 // Some types, as an extension, are stored in the variant. The Standard
38 // requires them to be observed as a handle.
39 template <class Context, class T>
test_handle(T value)40 void test_handle(T value) {
41 auto store = std::make_format_args<Context>(value);
42 std::basic_format_args<Context> format_args{store};
43
44 std::visit_format_arg(
45 [](auto a) { assert((std::is_same_v<decltype(a), typename std::basic_format_arg<Context>::handle>)); },
46 format_args.get(0));
47 }
48
49 // Test specific for string and string_view.
50 //
51 // Since both result in a string_view there's no need to pass this as a
52 // template argument.
53 template <class Context, class From>
test_string_view(From value)54 void test_string_view(From value) {
55 auto store = std::make_format_args<Context>(value);
56 const std::basic_format_args<Context> format_args{store};
57
58 using CharT = typename Context::char_type;
59 using To = std::basic_string_view<CharT>;
60 using V = std::basic_string<CharT>;
61 std::visit_format_arg(
62 [v = V(value.begin(), value.end())](auto a) {
63 if constexpr (std::is_same_v<To, decltype(a)>)
64 assert(v == a);
65 else
66 assert(false);
67 },
68 format_args.get(0));
69 }
70
71 template <class CharT>
test()72 void test() {
73 using Context = std::basic_format_context<CharT*, CharT>;
74 {
75 const std::basic_format_args<Context> format_args{};
76 ASSERT_NOEXCEPT(format_args.get(0));
77 assert(!format_args.get(0));
78 }
79
80 using char_type = typename Context::char_type;
81 std::basic_string<char_type> empty;
82 std::basic_string<char_type> str = MAKE_STRING(char_type, "abc");
83
84 // Test boolean types.
85
86 test<Context, bool>(true);
87 test<Context, bool>(false);
88
89 // Test char_type types.
90
91 test<Context, char_type, char_type>('a');
92 test<Context, char_type, char_type>('z');
93 test<Context, char_type, char_type>('0');
94 test<Context, char_type, char_type>('9');
95
96 // Test char types.
97
98 if (std::is_same_v<char_type, char>) {
99 // char to char -> char
100 test<Context, char_type, char>('a');
101 test<Context, char_type, char>('z');
102 test<Context, char_type, char>('0');
103 test<Context, char_type, char>('9');
104 } else {
105 if (std::is_same_v<char_type, wchar_t>) {
106 // char to wchar_t -> wchar_t
107 test<Context, wchar_t, char>('a');
108 test<Context, wchar_t, char>('z');
109 test<Context, wchar_t, char>('0');
110 test<Context, wchar_t, char>('9');
111 } else if (std::is_signed_v<char>) {
112 // char to char_type -> int
113 // This happens when Context::char_type is a char8_t, char16_t, or
114 // char32_t and char is a signed type.
115 // Note if sizeof(char_type) > sizeof(int) this test fails. If there are
116 // platforms where that occurs extra tests need to be added for char32_t
117 // testing it against a long long.
118 test<Context, int, char>('a');
119 test<Context, int, char>('z');
120 test<Context, int, char>('0');
121 test<Context, int, char>('9');
122 } else {
123 // char to char_type -> unsigned
124 // This happens when Context::char_type is a char8_t, char16_t, or
125 // char32_t and char is an unsigned type.
126 // Note if sizeof(char_type) > sizeof(unsigned) this test fails. If there
127 // are platforms where that occurs extra tests need to be added for
128 // char32_t testing it against an unsigned long long.
129 test<Context, unsigned, char>('a');
130 test<Context, unsigned, char>('z');
131 test<Context, unsigned, char>('0');
132 test<Context, unsigned, char>('9');
133 }
134 }
135
136 // Test signed integer types.
137
138 test<Context, int, signed char>(std::numeric_limits<signed char>::min());
139 test<Context, int, signed char>(0);
140 test<Context, int, signed char>(std::numeric_limits<signed char>::max());
141
142 test<Context, int, short>(std::numeric_limits<short>::min());
143 test<Context, int, short>(std::numeric_limits<signed char>::min());
144 test<Context, int, short>(0);
145 test<Context, int, short>(std::numeric_limits<signed char>::max());
146 test<Context, int, short>(std::numeric_limits<short>::max());
147
148 test<Context, int, int>(std::numeric_limits<int>::min());
149 test<Context, int, int>(std::numeric_limits<short>::min());
150 test<Context, int, int>(std::numeric_limits<signed char>::min());
151 test<Context, int, int>(0);
152 test<Context, int, int>(std::numeric_limits<signed char>::max());
153 test<Context, int, int>(std::numeric_limits<short>::max());
154 test<Context, int, int>(std::numeric_limits<int>::max());
155
156 using LongToType =
157 std::conditional_t<sizeof(long) == sizeof(int), int, long long>;
158
159 test<Context, LongToType, long>(std::numeric_limits<long>::min());
160 test<Context, LongToType, long>(std::numeric_limits<int>::min());
161 test<Context, LongToType, long>(std::numeric_limits<short>::min());
162 test<Context, LongToType, long>(std::numeric_limits<signed char>::min());
163 test<Context, LongToType, long>(0);
164 test<Context, LongToType, long>(std::numeric_limits<signed char>::max());
165 test<Context, LongToType, long>(std::numeric_limits<short>::max());
166 test<Context, LongToType, long>(std::numeric_limits<int>::max());
167 test<Context, LongToType, long>(std::numeric_limits<long>::max());
168
169 test<Context, long long, long long>(std::numeric_limits<long long>::min());
170 test<Context, long long, long long>(std::numeric_limits<long>::min());
171 test<Context, long long, long long>(std::numeric_limits<int>::min());
172 test<Context, long long, long long>(std::numeric_limits<short>::min());
173 test<Context, long long, long long>(std::numeric_limits<signed char>::min());
174 test<Context, long long, long long>(0);
175 test<Context, long long, long long>(std::numeric_limits<signed char>::max());
176 test<Context, long long, long long>(std::numeric_limits<short>::max());
177 test<Context, long long, long long>(std::numeric_limits<int>::max());
178 test<Context, long long, long long>(std::numeric_limits<long>::max());
179 test<Context, long long, long long>(std::numeric_limits<long long>::max());
180
181 #ifndef TEST_HAS_NO_INT128
182 test_handle<Context, __int128_t>(0);
183 #endif // TEST_HAS_NO_INT128
184
185 // Test unsigned integer types.
186
187 test<Context, unsigned, unsigned char>(0);
188 test<Context, unsigned, unsigned char>(
189 std::numeric_limits<unsigned char>::max());
190
191 test<Context, unsigned, unsigned short>(0);
192 test<Context, unsigned, unsigned short>(
193 std::numeric_limits<unsigned char>::max());
194 test<Context, unsigned, unsigned short>(
195 std::numeric_limits<unsigned short>::max());
196
197 test<Context, unsigned, unsigned>(0);
198 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned char>::max());
199 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned short>::max());
200 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned>::max());
201
202 using UnsignedLongToType =
203 std::conditional_t<sizeof(unsigned long) == sizeof(unsigned), unsigned,
204 unsigned long long>;
205
206 test<Context, UnsignedLongToType, unsigned long>(0);
207 test<Context, UnsignedLongToType, unsigned long>(
208 std::numeric_limits<unsigned char>::max());
209 test<Context, UnsignedLongToType, unsigned long>(
210 std::numeric_limits<unsigned short>::max());
211 test<Context, UnsignedLongToType, unsigned long>(
212 std::numeric_limits<unsigned>::max());
213 test<Context, UnsignedLongToType, unsigned long>(
214 std::numeric_limits<unsigned long>::max());
215
216 test<Context, unsigned long long, unsigned long long>(0);
217 test<Context, unsigned long long, unsigned long long>(
218 std::numeric_limits<unsigned char>::max());
219 test<Context, unsigned long long, unsigned long long>(
220 std::numeric_limits<unsigned short>::max());
221 test<Context, unsigned long long, unsigned long long>(
222 std::numeric_limits<unsigned>::max());
223 test<Context, unsigned long long, unsigned long long>(
224 std::numeric_limits<unsigned long>::max());
225 test<Context, unsigned long long, unsigned long long>(
226 std::numeric_limits<unsigned long long>::max());
227
228 #ifndef TEST_HAS_NO_INT128
229 test_handle<Context, __uint128_t>(0);
230 #endif // TEST_HAS_NO_INT128
231
232 // Test floating point types.
233
234 test<Context, float, float>(-std::numeric_limits<float>::max());
235 test<Context, float, float>(-std::numeric_limits<float>::min());
236 test<Context, float, float>(-0.0);
237 test<Context, float, float>(0.0);
238 test<Context, float, float>(std::numeric_limits<float>::min());
239 test<Context, float, float>(std::numeric_limits<float>::max());
240
241 test<Context, double, double>(-std::numeric_limits<double>::max());
242 test<Context, double, double>(-std::numeric_limits<double>::min());
243 test<Context, double, double>(-0.0);
244 test<Context, double, double>(0.0);
245 test<Context, double, double>(std::numeric_limits<double>::min());
246 test<Context, double, double>(std::numeric_limits<double>::max());
247
248 test<Context, long double, long double>(
249 -std::numeric_limits<long double>::max());
250 test<Context, long double, long double>(
251 -std::numeric_limits<long double>::min());
252 test<Context, long double, long double>(-0.0);
253 test<Context, long double, long double>(0.0);
254 test<Context, long double, long double>(
255 std::numeric_limits<long double>::min());
256 test<Context, long double, long double>(
257 std::numeric_limits<long double>::max());
258
259 // Test const char_type pointer types.
260
261 test<Context, const char_type*, const char_type*>(empty.c_str());
262 test<Context, const char_type*, const char_type*>(str.c_str());
263
264 // Test string_view types.
265
266 test<Context, std::basic_string_view<char_type>>(
267 std::basic_string_view<char_type>());
268 test<Context, std::basic_string_view<char_type>,
269 std::basic_string_view<char_type>>(empty);
270 test<Context, std::basic_string_view<char_type>,
271 std::basic_string_view<char_type>>(str);
272
273 // Test string types.
274
275 test<Context, std::basic_string_view<char_type>>(
276 std::basic_string<char_type>());
277 test<Context, std::basic_string_view<char_type>,
278 std::basic_string<char_type>>(empty);
279 test<Context, std::basic_string_view<char_type>,
280 std::basic_string<char_type>>(str);
281
282 // Test pointer types.
283
284 test<Context, const void*>(nullptr);
285 }
286
test()287 void test() {
288 test<char>();
289 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
290 test<wchar_t>();
291 #endif
292 }
293
main(int,char **)294 int main(int, char**) {
295 test();
296
297 return 0;
298 }
299