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
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
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.
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
41 /// When the type in the chrono-format-spec isn't present in the data a
42 /// \ref format_error is thrown.
47 __time
= __hour
| __minute
| __second
,
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
,
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
;
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
)
151 _ConstIterator __last
= __parse_chrono_specs(__begin
, __end
, __flags
);
152 __chrono_specs_
= basic_string_view
<_CharT
>{__begin
, __last
};
157 __parser
<_CharT
> __parser_
;
158 basic_string_view
<_CharT
> __chrono_specs_
;
161 _LIBCPP_HIDE_FROM_ABI
constexpr _ConstIterator
162 __parse_chrono_specs(_ConstIterator __begin
, _ConstIterator __end
, __flags __flags
) {
163 _LIBCPP_ASSERT_UNCATEGORIZED(
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 '}'");
174 std::__throw_format_error("The chrono specifiers contain a '{'");
180 __parse_conversion_spec(__begin
, __end
, __flags
);
184 // All other literals
188 } while (__begin
!= __end
&& *__begin
!= _CharT('}'));
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
) {
198 if (__begin
== __end
)
199 std::__throw_format_error("End of input while parsing a conversion specifier");
208 __format_spec::__validate_second(__flags
);
212 __format_spec::__validate_minute(__flags
);
215 case _CharT('p'): // TODO FMT does the formater require an hour or a time?
218 __parser_
.__hour_
= true;
219 __validate_hour(__flags
);
226 __parser_
.__hour_
= true;
227 __format_spec::__validate_time(__flags
);
232 __format_spec::__validate_day(__flags
);
238 __parser_
.__month_name_
= true;
241 __format_spec::__validate_month(__flags
);
247 __format_spec::__validate_year(__flags
);
251 __parser_
.__day_of_year_
= true;
252 __format_spec::__validate_date_or_duration(__flags
);
260 __parser_
.__week_of_year_
= true;
265 __format_spec::__validate_date(__flags
);
269 __format_spec::__validate_date_time(__flags
);
274 __parser_
.__weekday_name_
= true;
278 __parser_
.__weekday_
= true;
279 __validate_weekday(__flags
);
280 __format_spec::__validate_weekday(__flags
);
285 __format_spec::__validate_duration(__flags
);
289 __parse_modifier_E(__begin
, __end
, __flags
);
293 __parse_modifier_O(__begin
, __end
, __flags
);
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
);
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
) {
314 if (__begin
== __end
)
315 std::__throw_format_error("End of input while parsing the modifier E");
319 __parser_
.__hour_
= true;
320 __format_spec::__validate_time(__flags
);
326 __format_spec::__validate_year(__flags
);
330 __format_spec::__validate_date(__flags
);
334 __format_spec::__validate_date_time(__flags
);
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
);
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
) {
354 if (__begin
== __end
)
355 std::__throw_format_error("End of input while parsing the modifier O");
359 __format_spec::__validate_second(__flags
);
363 __format_spec::__validate_minute(__flags
);
368 __parser_
.__hour_
= true;
369 __format_spec::__validate_hour(__flags
);
374 __format_spec::__validate_day(__flags
);
378 __format_spec::__validate_month(__flags
);
382 __format_spec::__validate_year(__flags
);
388 __parser_
.__week_of_year_
= true;
389 __format_spec::__validate_date(__flags
);
394 __parser_
.__weekday_
= true;
395 __format_spec::__validate_weekday(__flags
);
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
);
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