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