Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / include / __chrono / parser_std_format_spec.h
blob296be8794ec59d94b6fc26186999b8e2135d3cae
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
11 #define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
13 #include <__config>
14 #include <__format/concepts.h>
15 #include <__format/format_error.h>
16 #include <__format/format_parse_context.h>
17 #include <__format/formatter_string.h>
18 #include <__format/parser_std_format_spec.h>
19 #include <string_view>
21 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22 # pragma GCC system_header
23 #endif
25 _LIBCPP_BEGIN_NAMESPACE_STD
27 #if _LIBCPP_STD_VER >= 20
29 namespace __format_spec {
31 // By not placing this constant in the formatter class it's not duplicated for char and wchar_t
32 inline constexpr __fields __fields_chrono_fractional{
33 .__precision_ = true, .__locale_specific_form_ = true, .__type_ = false};
34 inline constexpr __fields __fields_chrono{.__locale_specific_form_ = true, .__type_ = false};
36 /// Flags available or required in a chrono type.
37 ///
38 /// The caller of the chrono formatter lists the types it has available and the
39 /// validation tests whether the requested type spec (e.g. %M) is available in
40 /// the formatter.
41 /// When the type in the chrono-format-spec isn't present in the data a
42 /// \ref format_error is thrown.
43 enum class __flags {
44 __second = 0x1,
45 __minute = 0x2,
46 __hour = 0x4,
47 __time = __hour | __minute | __second,
49 __day = 0x8,
50 __month = 0x10,
51 __year = 0x20,
53 __weekday = 0x40,
55 __month_day = __day | __month,
56 __month_weekday = __weekday | __month,
57 __year_month = __month | __year,
58 __date = __day | __month | __year | __weekday,
60 __date_time = __date | __time,
62 __duration = 0x80 | __time,
64 __time_zone = 0x100,
66 __clock = __date_time | __time_zone
69 _LIBCPP_HIDE_FROM_ABI constexpr __flags operator&(__flags __lhs, __flags __rhs) {
70 return static_cast<__flags>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs));
73 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_second(__flags __flags) {
74 if ((__flags & __flags::__second) != __flags::__second)
75 std::__throw_format_error("The supplied date time doesn't contain a second");
78 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_minute(__flags __flags) {
79 if ((__flags & __flags::__minute) != __flags::__minute)
80 std::__throw_format_error("The supplied date time doesn't contain a minute");
83 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_hour(__flags __flags) {
84 if ((__flags & __flags::__hour) != __flags::__hour)
85 std::__throw_format_error("The supplied date time doesn't contain an hour");
88 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_time(__flags __flags) {
89 if ((__flags & __flags::__time) != __flags::__time)
90 std::__throw_format_error("The supplied date time doesn't contain a time");
93 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_day(__flags __flags) {
94 if ((__flags & __flags::__day) != __flags::__day)
95 std::__throw_format_error("The supplied date time doesn't contain a day");
98 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_month(__flags __flags) {
99 if ((__flags & __flags::__month) != __flags::__month)
100 std::__throw_format_error("The supplied date time doesn't contain a month");
103 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_year(__flags __flags) {
104 if ((__flags & __flags::__year) != __flags::__year)
105 std::__throw_format_error("The supplied date time doesn't contain a year");
108 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date(__flags __flags) {
109 if ((__flags & __flags::__date) != __flags::__date)
110 std::__throw_format_error("The supplied date time doesn't contain a date");
113 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_or_duration(__flags __flags) {
114 if (((__flags & __flags::__date) != __flags::__date) && ((__flags & __flags::__duration) != __flags::__duration))
115 std::__throw_format_error("The supplied date time doesn't contain a date or duration");
118 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_time(__flags __flags) {
119 if ((__flags & __flags::__date_time) != __flags::__date_time)
120 std::__throw_format_error("The supplied date time doesn't contain a date and time");
123 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_weekday(__flags __flags) {
124 if ((__flags & __flags::__weekday) != __flags::__weekday)
125 std::__throw_format_error("The supplied date time doesn't contain a weekday");
128 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_duration(__flags __flags) {
129 if ((__flags & __flags::__duration) != __flags::__duration)
130 std::__throw_format_error("The supplied date time doesn't contain a duration");
133 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_time_zone(__flags __flags) {
134 if ((__flags & __flags::__time_zone) != __flags::__time_zone)
135 std::__throw_format_error("The supplied date time doesn't contain a time zone");
138 template <class _CharT>
139 class _LIBCPP_TEMPLATE_VIS __parser_chrono {
140 using _ConstIterator = typename basic_format_parse_context<_CharT>::const_iterator;
142 public:
143 template <class _ParseContext>
144 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
145 __parse(_ParseContext& __ctx, __fields __fields, __flags __flags) {
146 _ConstIterator __begin = __parser_.__parse(__ctx, __fields);
147 _ConstIterator __end = __ctx.end();
148 if (__begin == __end)
149 return __begin;
151 _ConstIterator __last = __parse_chrono_specs(__begin, __end, __flags);
152 __chrono_specs_ = basic_string_view<_CharT>{__begin, __last};
154 return __last;
157 __parser<_CharT> __parser_;
158 basic_string_view<_CharT> __chrono_specs_;
160 private:
161 _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
162 __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
163 _LIBCPP_ASSERT_UNCATEGORIZED(
164 __begin != __end,
165 "When called with an empty input the function will cause "
166 "undefined behavior by evaluating data not in the input");
168 if (*__begin != _CharT('%') && *__begin != _CharT('}'))
169 std::__throw_format_error("The format specifier expects a '%' or a '}'");
171 do {
172 switch (*__begin) {
173 case _CharT('{'):
174 std::__throw_format_error("The chrono specifiers contain a '{'");
176 case _CharT('}'):
177 return __begin;
179 case _CharT('%'):
180 __parse_conversion_spec(__begin, __end, __flags);
181 [[fallthrough]];
183 default:
184 // All other literals
185 ++__begin;
188 } while (__begin != __end && *__begin != _CharT('}'));
190 return __begin;
193 /// \pre *__begin == '%'
194 /// \post __begin points at the end parsed conversion-spec
195 _LIBCPP_HIDE_FROM_ABI constexpr void
196 __parse_conversion_spec(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
197 ++__begin;
198 if (__begin == __end)
199 std::__throw_format_error("End of input while parsing a conversion specifier");
201 switch (*__begin) {
202 case _CharT('n'):
203 case _CharT('t'):
204 case _CharT('%'):
205 break;
207 case _CharT('S'):
208 __format_spec::__validate_second(__flags);
209 break;
211 case _CharT('M'):
212 __format_spec::__validate_minute(__flags);
213 break;
215 case _CharT('p'): // TODO FMT does the formater require an hour or a time?
216 case _CharT('H'):
217 case _CharT('I'):
218 __parser_.__hour_ = true;
219 __validate_hour(__flags);
220 break;
222 case _CharT('r'):
223 case _CharT('R'):
224 case _CharT('T'):
225 case _CharT('X'):
226 __parser_.__hour_ = true;
227 __format_spec::__validate_time(__flags);
228 break;
230 case _CharT('d'):
231 case _CharT('e'):
232 __format_spec::__validate_day(__flags);
233 break;
235 case _CharT('b'):
236 case _CharT('h'):
237 case _CharT('B'):
238 __parser_.__month_name_ = true;
239 [[fallthrough]];
240 case _CharT('m'):
241 __format_spec::__validate_month(__flags);
242 break;
244 case _CharT('y'):
245 case _CharT('C'):
246 case _CharT('Y'):
247 __format_spec::__validate_year(__flags);
248 break;
250 case _CharT('j'):
251 __parser_.__day_of_year_ = true;
252 __format_spec::__validate_date_or_duration(__flags);
253 break;
255 case _CharT('g'):
256 case _CharT('G'):
257 case _CharT('U'):
258 case _CharT('V'):
259 case _CharT('W'):
260 __parser_.__week_of_year_ = true;
261 [[fallthrough]];
262 case _CharT('x'):
263 case _CharT('D'):
264 case _CharT('F'):
265 __format_spec::__validate_date(__flags);
266 break;
268 case _CharT('c'):
269 __format_spec::__validate_date_time(__flags);
270 break;
272 case _CharT('a'):
273 case _CharT('A'):
274 __parser_.__weekday_name_ = true;
275 [[fallthrough]];
276 case _CharT('u'):
277 case _CharT('w'):
278 __parser_.__weekday_ = true;
279 __validate_weekday(__flags);
280 __format_spec::__validate_weekday(__flags);
281 break;
283 case _CharT('q'):
284 case _CharT('Q'):
285 __format_spec::__validate_duration(__flags);
286 break;
288 case _CharT('E'):
289 __parse_modifier_E(__begin, __end, __flags);
290 break;
292 case _CharT('O'):
293 __parse_modifier_O(__begin, __end, __flags);
294 break;
296 case _CharT('z'):
297 case _CharT('Z'):
298 // Currently there's no time zone information. However some clocks have a
299 // hard-coded "time zone", for these clocks the information can be used.
300 // TODO FMT implement time zones.
301 __format_spec::__validate_time_zone(__flags);
302 break;
304 default: // unknown type;
305 std::__throw_format_error("The date time type specifier is invalid");
309 /// \pre *__begin == 'E'
310 /// \post __begin is incremented by one.
311 _LIBCPP_HIDE_FROM_ABI constexpr void
312 __parse_modifier_E(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
313 ++__begin;
314 if (__begin == __end)
315 std::__throw_format_error("End of input while parsing the modifier E");
317 switch (*__begin) {
318 case _CharT('X'):
319 __parser_.__hour_ = true;
320 __format_spec::__validate_time(__flags);
321 break;
323 case _CharT('y'):
324 case _CharT('C'):
325 case _CharT('Y'):
326 __format_spec::__validate_year(__flags);
327 break;
329 case _CharT('x'):
330 __format_spec::__validate_date(__flags);
331 break;
333 case _CharT('c'):
334 __format_spec::__validate_date_time(__flags);
335 break;
337 case _CharT('z'):
338 // Currently there's no time zone information. However some clocks have a
339 // hard-coded "time zone", for these clocks the information can be used.
340 // TODO FMT implement time zones.
341 __format_spec::__validate_time_zone(__flags);
342 break;
344 default:
345 std::__throw_format_error("The date time type specifier for modifier E is invalid");
349 /// \pre *__begin == 'O'
350 /// \post __begin is incremented by one.
351 _LIBCPP_HIDE_FROM_ABI constexpr void
352 __parse_modifier_O(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
353 ++__begin;
354 if (__begin == __end)
355 std::__throw_format_error("End of input while parsing the modifier O");
357 switch (*__begin) {
358 case _CharT('S'):
359 __format_spec::__validate_second(__flags);
360 break;
362 case _CharT('M'):
363 __format_spec::__validate_minute(__flags);
364 break;
366 case _CharT('I'):
367 case _CharT('H'):
368 __parser_.__hour_ = true;
369 __format_spec::__validate_hour(__flags);
370 break;
372 case _CharT('d'):
373 case _CharT('e'):
374 __format_spec::__validate_day(__flags);
375 break;
377 case _CharT('m'):
378 __format_spec::__validate_month(__flags);
379 break;
381 case _CharT('y'):
382 __format_spec::__validate_year(__flags);
383 break;
385 case _CharT('U'):
386 case _CharT('V'):
387 case _CharT('W'):
388 __parser_.__week_of_year_ = true;
389 __format_spec::__validate_date(__flags);
390 break;
392 case _CharT('u'):
393 case _CharT('w'):
394 __parser_.__weekday_ = true;
395 __format_spec::__validate_weekday(__flags);
396 break;
398 case _CharT('z'):
399 // Currently there's no time zone information. However some clocks have a
400 // hard-coded "time zone", for these clocks the information can be used.
401 // TODO FMT implement time zones.
402 __format_spec::__validate_time_zone(__flags);
403 break;
405 default:
406 std::__throw_format_error("The date time type specifier for modifier O is invalid");
411 } // namespace __format_spec
413 #endif //_LIBCPP_STD_VER >= 20
415 _LIBCPP_END_NAMESPACE_STD
417 #endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H