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 | |
32 | namespace __format_spec { |
33 | |
34 | // By not placing this constant in the formatter class it's not duplicated for char and wchar_t |
35 | inline constexpr __fields __fields_chrono_fractional{ |
36 | .__precision_ = true, .__locale_specific_form_ = true, .__type_ = false}; |
37 | inline 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. |
46 | enum 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 | |
141 | template <class _CharT> |
142 | class __parser_chrono { |
143 | using _ConstIterator _LIBCPP_NODEBUG = typename basic_format_parse_context<_CharT>::const_iterator; |
144 | |
145 | public: |
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 | |
163 | private: |
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.