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