2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
11 #define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
15 #if _LIBCPP_HAS_LOCALIZATION
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>
24 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25 # pragma GCC system_header
28 _LIBCPP_BEGIN_NAMESPACE_STD
30 # if _LIBCPP_STD_VER >= 20
32 namespace __format_spec
{
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};
39 /// Flags available or required in a chrono type.
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
44 /// When the type in the chrono-format-spec isn't present in the data a
45 /// \ref format_error is thrown.
50 __time
= __hour
| __minute
| __second
,
58 __month_day
= __day
| __month
,
59 __month_weekday
= __weekday
| __month
,
60 __year_month
= __month
| __year
,
61 __date
= __day
| __month
| __year
| __weekday
,
63 __date_time
= __date
| __time
,
65 __duration
= 0x80 | __time
,
69 __clock
= __date_time
| __time_zone
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
));
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
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");
141 template <class _CharT
>
142 class _LIBCPP_TEMPLATE_VIS __parser_chrono
{
143 using _ConstIterator
= typename basic_format_parse_context
<_CharT
>::const_iterator
;
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
)
154 _ConstIterator __last
= __parse_chrono_specs(__begin
, __end
, __flags
);
155 __chrono_specs_
= basic_string_view
<_CharT
>{__begin
, __last
};
160 __parser
<_CharT
> __parser_
;
161 basic_string_view
<_CharT
> __chrono_specs_
;
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");
170 if (*__begin
!= _CharT('%') && *__begin
!= _CharT('}'))
171 std::__throw_format_error("The format specifier expects a '%' or a '}'");
176 std::__throw_format_error("The chrono specifiers contain a '{'");
182 __parse_conversion_spec(__begin
, __end
, __flags
);
186 // All other literals
190 } while (__begin
!= __end
&& *__begin
!= _CharT('}'));
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
) {
200 if (__begin
== __end
)
201 std::__throw_format_error("End of input while parsing a conversion specifier");
210 __format_spec::__validate_second(__flags
);
214 __format_spec::__validate_minute(__flags
);
217 case _CharT('p'): // TODO FMT does the formater require an hour or a time?
220 __parser_
.__hour_
= true;
221 __validate_hour(__flags
);
228 __parser_
.__hour_
= true;
229 __format_spec::__validate_time(__flags
);
234 __format_spec::__validate_day(__flags
);
240 __parser_
.__month_name_
= true;
243 __format_spec::__validate_month(__flags
);
249 __format_spec::__validate_year(__flags
);
253 __parser_
.__day_of_year_
= true;
254 __format_spec::__validate_date_or_duration(__flags
);
262 __parser_
.__week_of_year_
= true;
267 __format_spec::__validate_date(__flags
);
271 __format_spec::__validate_date_time(__flags
);
276 __parser_
.__weekday_name_
= true;
280 __parser_
.__weekday_
= true;
281 __validate_weekday(__flags
);
282 __format_spec::__validate_weekday(__flags
);
287 __format_spec::__validate_duration(__flags
);
291 __parse_modifier_E(__begin
, __end
, __flags
);
295 __parse_modifier_O(__begin
, __end
, __flags
);
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
);
306 default: // unknown type;
307 std::__throw_format_error("The date time type specifier is invalid");
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
) {
316 if (__begin
== __end
)
317 std::__throw_format_error("End of input while parsing the modifier E");
321 __parser_
.__hour_
= true;
322 __format_spec::__validate_time(__flags
);
328 __format_spec::__validate_year(__flags
);
332 __format_spec::__validate_date(__flags
);
336 __format_spec::__validate_date_time(__flags
);
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
);
347 std::__throw_format_error("The date time type specifier for modifier E is invalid");
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
) {
356 if (__begin
== __end
)
357 std::__throw_format_error("End of input while parsing the modifier O");
361 __format_spec::__validate_second(__flags
);
365 __format_spec::__validate_minute(__flags
);
370 __parser_
.__hour_
= true;
371 __format_spec::__validate_hour(__flags
);
376 __format_spec::__validate_day(__flags
);
380 __format_spec::__validate_month(__flags
);
384 __format_spec::__validate_year(__flags
);
390 __parser_
.__week_of_year_
= true;
391 __format_spec::__validate_date(__flags
);
396 __parser_
.__weekday_
= true;
397 __format_spec::__validate_weekday(__flags
);
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
);
408 std::__throw_format_error("The date time type specifier for modifier O is invalid");
413 } // namespace __format_spec
415 # endif // _LIBCPP_STD_VER >= 20
417 _LIBCPP_END_NAMESPACE_STD
419 #endif // _LIBCPP_HAS_LOCALIZATION
421 #endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H