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