Warning: This file is not a C or C++ file. It does not have highlighting.

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//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
11#define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
12
13#include <__config>
14
15#if _LIBCPP_HAS_LOCALIZATION
16
17# include <__format/concepts.h>
18# include <__format/format_error.h>
19# include <__format/format_parse_context.h>
20# include <__format/formatter_string.h>
21# include <__format/parser_std_format_spec.h>
22# include <string_view>
23
24# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25# pragma GCC system_header
26# endif
27
28_LIBCPP_BEGIN_NAMESPACE_STD
29
30# if _LIBCPP_STD_VER >= 20
31
32namespace __format_spec {
33
34// By not placing this constant in the formatter class it's not duplicated for char and wchar_t
35inline constexpr __fields __fields_chrono_fractional{
36 .__precision_ = true, .__locale_specific_form_ = true, .__type_ = false};
37inline constexpr __fields __fields_chrono{.__locale_specific_form_ = true, .__type_ = false};
38
39/// Flags available or required in a chrono type.
40///
41/// The caller of the chrono formatter lists the types it has available and the
42/// validation tests whether the requested type spec (e.g. %M) is available in
43/// the formatter.
44/// When the type in the chrono-format-spec isn't present in the data a
45/// \ref format_error is thrown.
46enum class __flags {
47 __second = 0x1,
48 __minute = 0x2,
49 __hour = 0x4,
50 __time = __hour | __minute | __second,
51
52 __day = 0x8,
53 __month = 0x10,
54 __year = 0x20,
55
56 __weekday = 0x40,
57
58 __month_day = __day | __month,
59 __month_weekday = __weekday | __month,
60 __year_month = __month | __year,
61 __date = __day | __month | __year | __weekday,
62
63 __date_time = __date | __time,
64
65 __duration = 0x80 | __time,
66
67 __time_zone = 0x100,
68
69 __clock = __date_time | __time_zone
70};
71
72_LIBCPP_HIDE_FROM_ABI constexpr __flags operator&(__flags __lhs, __flags __rhs) {
73 return static_cast<__flags>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs));
74}
75
76_LIBCPP_HIDE_FROM_ABI constexpr void __validate_second(__flags __flags) {
77 if ((__flags & __flags::__second) != __flags::__second)
78 std::__throw_format_error("The supplied date time doesn't contain a second");
79}
80
81_LIBCPP_HIDE_FROM_ABI constexpr void __validate_minute(__flags __flags) {
82 if ((__flags & __flags::__minute) != __flags::__minute)
83 std::__throw_format_error("The supplied date time doesn't contain a minute");
84}
85
86_LIBCPP_HIDE_FROM_ABI constexpr void __validate_hour(__flags __flags) {
87 if ((__flags & __flags::__hour) != __flags::__hour)
88 std::__throw_format_error("The supplied date time doesn't contain an hour");
89}
90
91_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time(__flags __flags) {
92 if ((__flags & __flags::__time) != __flags::__time)
93 std::__throw_format_error("The supplied date time doesn't contain a time");
94}
95
96_LIBCPP_HIDE_FROM_ABI constexpr void __validate_day(__flags __flags) {
97 if ((__flags & __flags::__day) != __flags::__day)
98 std::__throw_format_error("The supplied date time doesn't contain a day");
99}
100
101_LIBCPP_HIDE_FROM_ABI constexpr void __validate_month(__flags __flags) {
102 if ((__flags & __flags::__month) != __flags::__month)
103 std::__throw_format_error("The supplied date time doesn't contain a month");
104}
105
106_LIBCPP_HIDE_FROM_ABI constexpr void __validate_year(__flags __flags) {
107 if ((__flags & __flags::__year) != __flags::__year)
108 std::__throw_format_error("The supplied date time doesn't contain a year");
109}
110
111_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date(__flags __flags) {
112 if ((__flags & __flags::__date) != __flags::__date)
113 std::__throw_format_error("The supplied date time doesn't contain a date");
114}
115
116_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_or_duration(__flags __flags) {
117 if (((__flags & __flags::__date) != __flags::__date) && ((__flags & __flags::__duration) != __flags::__duration))
118 std::__throw_format_error("The supplied date time doesn't contain a date or duration");
119}
120
121_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_time(__flags __flags) {
122 if ((__flags & __flags::__date_time) != __flags::__date_time)
123 std::__throw_format_error("The supplied date time doesn't contain a date and time");
124}
125
126_LIBCPP_HIDE_FROM_ABI constexpr void __validate_weekday(__flags __flags) {
127 if ((__flags & __flags::__weekday) != __flags::__weekday)
128 std::__throw_format_error("The supplied date time doesn't contain a weekday");
129}
130
131_LIBCPP_HIDE_FROM_ABI constexpr void __validate_duration(__flags __flags) {
132 if ((__flags & __flags::__duration) != __flags::__duration)
133 std::__throw_format_error("The supplied date time doesn't contain a duration");
134}
135
136_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time_zone(__flags __flags) {
137 if ((__flags & __flags::__time_zone) != __flags::__time_zone)
138 std::__throw_format_error("The supplied date time doesn't contain a time zone");
139}
140
141template <class _CharT>
142class __parser_chrono {
143 using _ConstIterator _LIBCPP_NODEBUG = typename basic_format_parse_context<_CharT>::const_iterator;
144
145public:
146 template <class _ParseContext>
147 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
148 __parse(_ParseContext& __ctx, __fields __fields, __flags __flags) {
149 _ConstIterator __begin = __parser_.__parse(__ctx, __fields);
150 _ConstIterator __end = __ctx.end();
151 if (__begin == __end)
152 return __begin;
153
154 _ConstIterator __last = __parse_chrono_specs(__begin, __end, __flags);
155 __chrono_specs_ = basic_string_view<_CharT>{__begin, __last};
156
157 return __last;
158 }
159
160 __parser<_CharT> __parser_;
161 basic_string_view<_CharT> __chrono_specs_;
162
163private:
164 _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
165 __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
166 _LIBCPP_ASSERT_INTERNAL(__begin != __end,
167 "When called with an empty input the function will cause "
168 "undefined behavior by evaluating data not in the input");
169
170 if (*__begin != _CharT('%') && *__begin != _CharT('}'))
171 std::__throw_format_error("The format specifier expects a '%' or a '}'");
172
173 do {
174 switch (*__begin) {
175 case _CharT('{'):
176 std::__throw_format_error("The chrono specifiers contain a '{'");
177
178 case _CharT('}'):
179 return __begin;
180
181 case _CharT('%'):
182 __parse_conversion_spec(__begin, __end, __flags);
183 [[fallthrough]];
184
185 default:
186 // All other literals
187 ++__begin;
188 }
189
190 } while (__begin != __end && *__begin != _CharT('}'));
191
192 return __begin;
193 }
194
195 /// \pre *__begin == '%'
196 /// \post __begin points at the end parsed conversion-spec
197 _LIBCPP_HIDE_FROM_ABI constexpr void
198 __parse_conversion_spec(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
199 ++__begin;
200 if (__begin == __end)
201 std::__throw_format_error("End of input while parsing a conversion specifier");
202
203 switch (*__begin) {
204 case _CharT('n'):
205 case _CharT('t'):
206 case _CharT('%'):
207 break;
208
209 case _CharT('S'):
210 __format_spec::__validate_second(__flags);
211 break;
212
213 case _CharT('M'):
214 __format_spec::__validate_minute(__flags);
215 break;
216
217 case _CharT('p'): // TODO FMT does the formater require an hour or a time?
218 case _CharT('H'):
219 case _CharT('I'):
220 __parser_.__hour_ = true;
221 __validate_hour(__flags);
222 break;
223
224 case _CharT('r'):
225 case _CharT('R'):
226 case _CharT('T'):
227 case _CharT('X'):
228 __parser_.__hour_ = true;
229 __format_spec::__validate_time(__flags);
230 break;
231
232 case _CharT('d'):
233 case _CharT('e'):
234 __format_spec::__validate_day(__flags);
235 break;
236
237 case _CharT('b'):
238 case _CharT('h'):
239 case _CharT('B'):
240 __parser_.__month_name_ = true;
241 [[fallthrough]];
242 case _CharT('m'):
243 __format_spec::__validate_month(__flags);
244 break;
245
246 case _CharT('y'):
247 case _CharT('C'):
248 case _CharT('Y'):
249 __format_spec::__validate_year(__flags);
250 break;
251
252 case _CharT('j'):
253 __parser_.__day_of_year_ = true;
254 __format_spec::__validate_date_or_duration(__flags);
255 break;
256
257 case _CharT('g'):
258 case _CharT('G'):
259 case _CharT('U'):
260 case _CharT('V'):
261 case _CharT('W'):
262 __parser_.__week_of_year_ = true;
263 [[fallthrough]];
264 case _CharT('x'):
265 case _CharT('D'):
266 case _CharT('F'):
267 __format_spec::__validate_date(__flags);
268 break;
269
270 case _CharT('c'):
271 __format_spec::__validate_date_time(__flags);
272 break;
273
274 case _CharT('a'):
275 case _CharT('A'):
276 __parser_.__weekday_name_ = true;
277 [[fallthrough]];
278 case _CharT('u'):
279 case _CharT('w'):
280 __parser_.__weekday_ = true;
281 __validate_weekday(__flags);
282 __format_spec::__validate_weekday(__flags);
283 break;
284
285 case _CharT('q'):
286 case _CharT('Q'):
287 __format_spec::__validate_duration(__flags);
288 break;
289
290 case _CharT('E'):
291 __parse_modifier_E(__begin, __end, __flags);
292 break;
293
294 case _CharT('O'):
295 __parse_modifier_O(__begin, __end, __flags);
296 break;
297
298 case _CharT('z'):
299 case _CharT('Z'):
300 // Currently there's no time zone information. However some clocks have a
301 // hard-coded "time zone", for these clocks the information can be used.
302 // TODO FMT implement time zones.
303 __format_spec::__validate_time_zone(__flags);
304 break;
305
306 default: // unknown type;
307 std::__throw_format_error("The date time type specifier is invalid");
308 }
309 }
310
311 /// \pre *__begin == 'E'
312 /// \post __begin is incremented by one.
313 _LIBCPP_HIDE_FROM_ABI constexpr void
314 __parse_modifier_E(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
315 ++__begin;
316 if (__begin == __end)
317 std::__throw_format_error("End of input while parsing the modifier E");
318
319 switch (*__begin) {
320 case _CharT('X'):
321 __parser_.__hour_ = true;
322 __format_spec::__validate_time(__flags);
323 break;
324
325 case _CharT('y'):
326 case _CharT('C'):
327 case _CharT('Y'):
328 __format_spec::__validate_year(__flags);
329 break;
330
331 case _CharT('x'):
332 __format_spec::__validate_date(__flags);
333 break;
334
335 case _CharT('c'):
336 __format_spec::__validate_date_time(__flags);
337 break;
338
339 case _CharT('z'):
340 // Currently there's no time zone information. However some clocks have a
341 // hard-coded "time zone", for these clocks the information can be used.
342 // TODO FMT implement time zones.
343 __format_spec::__validate_time_zone(__flags);
344 break;
345
346 default:
347 std::__throw_format_error("The date time type specifier for modifier E is invalid");
348 }
349 }
350
351 /// \pre *__begin == 'O'
352 /// \post __begin is incremented by one.
353 _LIBCPP_HIDE_FROM_ABI constexpr void
354 __parse_modifier_O(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
355 ++__begin;
356 if (__begin == __end)
357 std::__throw_format_error("End of input while parsing the modifier O");
358
359 switch (*__begin) {
360 case _CharT('S'):
361 __format_spec::__validate_second(__flags);
362 break;
363
364 case _CharT('M'):
365 __format_spec::__validate_minute(__flags);
366 break;
367
368 case _CharT('I'):
369 case _CharT('H'):
370 __parser_.__hour_ = true;
371 __format_spec::__validate_hour(__flags);
372 break;
373
374 case _CharT('d'):
375 case _CharT('e'):
376 __format_spec::__validate_day(__flags);
377 break;
378
379 case _CharT('m'):
380 __format_spec::__validate_month(__flags);
381 break;
382
383 case _CharT('y'):
384 __format_spec::__validate_year(__flags);
385 break;
386
387 case _CharT('U'):
388 case _CharT('V'):
389 case _CharT('W'):
390 __parser_.__week_of_year_ = true;
391 __format_spec::__validate_date(__flags);
392 break;
393
394 case _CharT('u'):
395 case _CharT('w'):
396 __parser_.__weekday_ = true;
397 __format_spec::__validate_weekday(__flags);
398 break;
399
400 case _CharT('z'):
401 // Currently there's no time zone information. However some clocks have a
402 // hard-coded "time zone", for these clocks the information can be used.
403 // TODO FMT implement time zones.
404 __format_spec::__validate_time_zone(__flags);
405 break;
406
407 default:
408 std::__throw_format_error("The date time type specifier for modifier O is invalid");
409 }
410 }
411};
412
413} // namespace __format_spec
414
415# endif // _LIBCPP_STD_VER >= 20
416
417_LIBCPP_END_NAMESPACE_STD
418
419#endif // _LIBCPP_HAS_LOCALIZATION
420
421#endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
422

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of libcxx/include/__chrono/parser_std_format_spec.h