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 // This test requires the dylib support introduced in D92214.
12 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
13
14 // <format>
15
16 // template<class Visitor, class Context>
17 // see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
18
19 #include <format>
20 #include <cassert>
21 #include <type_traits>
22
23 #include "constexpr_char_traits.h"
24 #include "test_macros.h"
25 #include "make_string.h"
26 #include "min_allocator.h"
27
28 template <class Context, class To, class From>
test(From value)29 void test(From value) {
30 auto store = std::make_format_args<Context>(value);
31 std::basic_format_args<Context> format_args{store};
32
33 assert(format_args.__size() == 1);
34 assert(format_args.get(0));
35
36 auto result = std::visit_format_arg(
37 [v = To(value)](auto a) -> To {
38 if constexpr (std::is_same_v<To, decltype(a)>) {
39 assert(v == a);
40 return a;
41 } else {
42 assert(false);
43 return {};
44 }
45 },
46 format_args.get(0));
47
48 using ct = std::common_type_t<From, To>;
49 assert(static_cast<ct>(result) == static_cast<ct>(value));
50 }
51
52 // Test specific for string and string_view.
53 //
54 // Since both result in a string_view there's no need to pass this as a
55 // template argument.
56 template <class Context, class From>
test_string_view(From value)57 void test_string_view(From value) {
58 auto store = std::make_format_args<Context>(value);
59 std::basic_format_args<Context> format_args{store};
60
61 assert(format_args.__size() == 1);
62 assert(format_args.get(0));
63
64 using CharT = typename Context::char_type;
65 using To = std::basic_string_view<CharT>;
66 using V = std::basic_string<CharT>;
67 auto result = std::visit_format_arg(
68 [v = V(value.begin(), value.end())](auto a) -> To {
69 if constexpr (std::is_same_v<To, decltype(a)>) {
70 assert(v == a);
71 return a;
72 } else {
73 assert(false);
74 return {};
75 }
76 },
77 format_args.get(0));
78
79 assert(std::equal(value.begin(), value.end(), result.begin(), result.end()));
80 }
81
82 template <class CharT>
test()83 void test() {
84 using Context = std::basic_format_context<CharT*, CharT>;
85 std::basic_string<CharT> empty;
86 std::basic_string<CharT> str = MAKE_STRING(CharT, "abc");
87
88 // Test boolean types.
89
90 test<Context, bool>(true);
91 test<Context, bool>(false);
92
93 // Test CharT types.
94
95 test<Context, CharT, CharT>('a');
96 test<Context, CharT, CharT>('z');
97 test<Context, CharT, CharT>('0');
98 test<Context, CharT, CharT>('9');
99
100 // Test char types.
101
102 if (std::is_same_v<CharT, char>) {
103 // char to char -> char
104 test<Context, CharT, char>('a');
105 test<Context, CharT, char>('z');
106 test<Context, CharT, char>('0');
107 test<Context, CharT, char>('9');
108 } else {
109 if (std::is_same_v<CharT, wchar_t>) {
110 // char to wchar_t -> wchar_t
111 test<Context, wchar_t, char>('a');
112 test<Context, wchar_t, char>('z');
113 test<Context, wchar_t, char>('0');
114 test<Context, wchar_t, char>('9');
115 } else if (std::is_signed_v<char>) {
116 // char to CharT -> int
117 // This happens when CharT is a char8_t, char16_t, or char32_t and char
118 // is a signed type.
119 // Note if sizeof(CharT) > sizeof(int) this test fails. If there are
120 // platforms where that occurs extra tests need to be added for char32_t
121 // testing it against a long long.
122 test<Context, int, char>('a');
123 test<Context, int, char>('z');
124 test<Context, int, char>('0');
125 test<Context, int, char>('9');
126 } else {
127 // char to CharT -> unsigned
128 // This happens when CharT is a char8_t, char16_t, or char32_t and char
129 // is an unsigned type.
130 // Note if sizeof(CharT) > sizeof(unsigned) this test fails. If there are
131 // platforms where that occurs extra tests need to be added for char32_t
132 // testing it against an unsigned long long.
133 test<Context, unsigned, char>('a');
134 test<Context, unsigned, char>('z');
135 test<Context, unsigned, char>('0');
136 test<Context, unsigned, char>('9');
137 }
138 }
139
140 // Test signed integer types.
141
142 test<Context, int, signed char>(std::numeric_limits<signed char>::min());
143 test<Context, int, signed char>(0);
144 test<Context, int, signed char>(std::numeric_limits<signed char>::max());
145
146 test<Context, int, short>(std::numeric_limits<short>::min());
147 test<Context, int, short>(std::numeric_limits<signed char>::min());
148 test<Context, int, short>(0);
149 test<Context, int, short>(std::numeric_limits<signed char>::max());
150 test<Context, int, short>(std::numeric_limits<short>::max());
151
152 test<Context, int, int>(std::numeric_limits<int>::min());
153 test<Context, int, int>(std::numeric_limits<short>::min());
154 test<Context, int, int>(std::numeric_limits<signed char>::min());
155 test<Context, int, int>(0);
156 test<Context, int, int>(std::numeric_limits<signed char>::max());
157 test<Context, int, int>(std::numeric_limits<short>::max());
158 test<Context, int, int>(std::numeric_limits<int>::max());
159
160 using LongToType =
161 std::conditional_t<sizeof(long) == sizeof(int), int, long long>;
162
163 test<Context, LongToType, long>(std::numeric_limits<long>::min());
164 test<Context, LongToType, long>(std::numeric_limits<int>::min());
165 test<Context, LongToType, long>(std::numeric_limits<short>::min());
166 test<Context, LongToType, long>(std::numeric_limits<signed char>::min());
167 test<Context, LongToType, long>(0);
168 test<Context, LongToType, long>(std::numeric_limits<signed char>::max());
169 test<Context, LongToType, long>(std::numeric_limits<short>::max());
170 test<Context, LongToType, long>(std::numeric_limits<int>::max());
171 test<Context, LongToType, long>(std::numeric_limits<long>::max());
172
173 test<Context, long long, long long>(std::numeric_limits<long long>::min());
174 test<Context, long long, long long>(std::numeric_limits<long>::min());
175 test<Context, long long, long long>(std::numeric_limits<int>::min());
176 test<Context, long long, long long>(std::numeric_limits<short>::min());
177 test<Context, long long, long long>(std::numeric_limits<signed char>::min());
178 test<Context, long long, long long>(0);
179 test<Context, long long, long long>(std::numeric_limits<signed char>::max());
180 test<Context, long long, long long>(std::numeric_limits<short>::max());
181 test<Context, long long, long long>(std::numeric_limits<int>::max());
182 test<Context, long long, long long>(std::numeric_limits<long>::max());
183 test<Context, long long, long long>(std::numeric_limits<long long>::max());
184
185 #ifndef TEST_HAS_NO_INT128
186 test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::min());
187 test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::min());
188 test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::min());
189 test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::min());
190 test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::min());
191 test<Context, __int128_t, __int128_t>(
192 std::numeric_limits<signed char>::min());
193 test<Context, __int128_t, __int128_t>(0);
194 test<Context, __int128_t, __int128_t>(
195 std::numeric_limits<signed char>::max());
196 test<Context, __int128_t, __int128_t>(std::numeric_limits<short>::max());
197 test<Context, __int128_t, __int128_t>(std::numeric_limits<int>::max());
198 test<Context, __int128_t, __int128_t>(std::numeric_limits<long>::max());
199 test<Context, __int128_t, __int128_t>(std::numeric_limits<long long>::max());
200 test<Context, __int128_t, __int128_t>(std::numeric_limits<__int128_t>::max());
201 #endif
202
203 // Test unsigned integer types.
204
205 test<Context, unsigned, unsigned char>(0);
206 test<Context, unsigned, unsigned char>(
207 std::numeric_limits<unsigned char>::max());
208
209 test<Context, unsigned, unsigned short>(0);
210 test<Context, unsigned, unsigned short>(
211 std::numeric_limits<unsigned char>::max());
212 test<Context, unsigned, unsigned short>(
213 std::numeric_limits<unsigned short>::max());
214
215 test<Context, unsigned, unsigned>(0);
216 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned char>::max());
217 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned short>::max());
218 test<Context, unsigned, unsigned>(std::numeric_limits<unsigned>::max());
219
220 using UnsignedLongToType =
221 std::conditional_t<sizeof(unsigned long) == sizeof(unsigned), unsigned,
222 unsigned long long>;
223
224 test<Context, UnsignedLongToType, unsigned long>(0);
225 test<Context, UnsignedLongToType, unsigned long>(
226 std::numeric_limits<unsigned char>::max());
227 test<Context, UnsignedLongToType, unsigned long>(
228 std::numeric_limits<unsigned short>::max());
229 test<Context, UnsignedLongToType, unsigned long>(
230 std::numeric_limits<unsigned>::max());
231 test<Context, UnsignedLongToType, unsigned long>(
232 std::numeric_limits<unsigned long>::max());
233
234 test<Context, unsigned long long, unsigned long long>(0);
235 test<Context, unsigned long long, unsigned long long>(
236 std::numeric_limits<unsigned char>::max());
237 test<Context, unsigned long long, unsigned long long>(
238 std::numeric_limits<unsigned short>::max());
239 test<Context, unsigned long long, unsigned long long>(
240 std::numeric_limits<unsigned>::max());
241 test<Context, unsigned long long, unsigned long long>(
242 std::numeric_limits<unsigned long>::max());
243 test<Context, unsigned long long, unsigned long long>(
244 std::numeric_limits<unsigned long long>::max());
245
246 #ifndef TEST_HAS_NO_INT128
247 test<Context, __uint128_t, __uint128_t>(0);
248 test<Context, __uint128_t, __uint128_t>(
249 std::numeric_limits<unsigned char>::max());
250 test<Context, __uint128_t, __uint128_t>(
251 std::numeric_limits<unsigned short>::max());
252 test<Context, __uint128_t, __uint128_t>(
253 std::numeric_limits<unsigned int>::max());
254 test<Context, __uint128_t, __uint128_t>(
255 std::numeric_limits<unsigned long>::max());
256 test<Context, __uint128_t, __uint128_t>(
257 std::numeric_limits<unsigned long long>::max());
258 test<Context, __uint128_t, __uint128_t>(
259 std::numeric_limits<__uint128_t>::max());
260 #endif
261
262 // Test floating point types.
263
264 test<Context, float, float>(-std::numeric_limits<float>::max());
265 test<Context, float, float>(-std::numeric_limits<float>::min());
266 test<Context, float, float>(-0.0);
267 test<Context, float, float>(0.0);
268 test<Context, float, float>(std::numeric_limits<float>::min());
269 test<Context, float, float>(std::numeric_limits<float>::max());
270
271 test<Context, double, double>(-std::numeric_limits<double>::max());
272 test<Context, double, double>(-std::numeric_limits<double>::min());
273 test<Context, double, double>(-0.0);
274 test<Context, double, double>(0.0);
275 test<Context, double, double>(std::numeric_limits<double>::min());
276 test<Context, double, double>(std::numeric_limits<double>::max());
277
278 test<Context, long double, long double>(
279 -std::numeric_limits<long double>::max());
280 test<Context, long double, long double>(
281 -std::numeric_limits<long double>::min());
282 test<Context, long double, long double>(-0.0);
283 test<Context, long double, long double>(0.0);
284 test<Context, long double, long double>(
285 std::numeric_limits<long double>::min());
286 test<Context, long double, long double>(
287 std::numeric_limits<long double>::max());
288
289 // Test const CharT pointer types.
290
291 test<Context, const CharT*, const CharT*>(empty.c_str());
292 test<Context, const CharT*, const CharT*>(str.c_str());
293
294 // Test string_view types.
295
296 {
297 using From = std::basic_string_view<CharT>;
298
299 test_string_view<Context>(From());
300 test_string_view<Context>(From(empty.c_str()));
301 test_string_view<Context>(From(str.c_str()));
302 }
303
304 {
305 using From = std::basic_string_view<CharT, constexpr_char_traits<CharT>>;
306
307 test_string_view<Context>(From());
308 test_string_view<Context>(From(empty.c_str()));
309 test_string_view<Context>(From(str.c_str()));
310 }
311
312 // Test string types.
313
314 {
315 using From = std::basic_string<CharT>;
316
317 test_string_view<Context>(From());
318 test_string_view<Context>(From(empty.c_str()));
319 test_string_view<Context>(From(str.c_str()));
320 }
321
322 {
323 using From = std::basic_string<CharT, constexpr_char_traits<CharT>,
324 std::allocator<CharT>>;
325
326 test_string_view<Context>(From());
327 test_string_view<Context>(From(empty.c_str()));
328 test_string_view<Context>(From(str.c_str()));
329 }
330
331 {
332 using From =
333 std::basic_string<CharT, std::char_traits<CharT>, min_allocator<CharT>>;
334
335 test_string_view<Context>(From());
336 test_string_view<Context>(From(empty.c_str()));
337 test_string_view<Context>(From(str.c_str()));
338 }
339
340 {
341 using From = std::basic_string<CharT, constexpr_char_traits<CharT>,
342 min_allocator<CharT>>;
343
344 test_string_view<Context>(From());
345 test_string_view<Context>(From(empty.c_str()));
346 test_string_view<Context>(From(str.c_str()));
347 }
348
349 // Test pointer types.
350
351 test<Context, const void*>(nullptr);
352 int i = 0;
353 test<Context, const void*>(static_cast<void*>(&i));
354 const int ci = 0;
355 test<Context, const void*>(static_cast<const void*>(&ci));
356 }
357
main(int,char **)358 int main(int, char**) {
359 test<char>();
360 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
361 test<wchar_t>();
362 #endif
363
364 return 0;
365 }
366