Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-03 08:13:15

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
0011 #define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
0012 
0013 #include <__config>
0014 
0015 #if _LIBCPP_HAS_LOCALIZATION
0016 
0017 #  include <__format/concepts.h>
0018 #  include <__format/format_error.h>
0019 #  include <__format/format_parse_context.h>
0020 #  include <__format/formatter_string.h>
0021 #  include <__format/parser_std_format_spec.h>
0022 #  include <string_view>
0023 
0024 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0025 #    pragma GCC system_header
0026 #  endif
0027 
0028 _LIBCPP_BEGIN_NAMESPACE_STD
0029 
0030 #  if _LIBCPP_STD_VER >= 20
0031 
0032 namespace __format_spec {
0033 
0034 // By not placing this constant in the formatter class it's not duplicated for char and wchar_t
0035 inline constexpr __fields __fields_chrono_fractional{
0036     .__precision_ = true, .__locale_specific_form_ = true, .__type_ = false};
0037 inline constexpr __fields __fields_chrono{.__locale_specific_form_ = true, .__type_ = false};
0038 
0039 /// Flags available or required in a chrono type.
0040 ///
0041 /// The caller of the chrono formatter lists the types it has available and the
0042 /// validation tests whether the requested type spec (e.g. %M) is available in
0043 /// the formatter.
0044 /// When the type in the chrono-format-spec isn't present in the data a
0045 /// \ref format_error is thrown.
0046 enum class __flags {
0047   __second = 0x1,
0048   __minute = 0x2,
0049   __hour   = 0x4,
0050   __time   = __hour | __minute | __second,
0051 
0052   __day   = 0x8,
0053   __month = 0x10,
0054   __year  = 0x20,
0055 
0056   __weekday = 0x40,
0057 
0058   __month_day     = __day | __month,
0059   __month_weekday = __weekday | __month,
0060   __year_month    = __month | __year,
0061   __date          = __day | __month | __year | __weekday,
0062 
0063   __date_time = __date | __time,
0064 
0065   __duration = 0x80 | __time,
0066 
0067   __time_zone = 0x100,
0068 
0069   __clock = __date_time | __time_zone
0070 };
0071 
0072 _LIBCPP_HIDE_FROM_ABI constexpr __flags operator&(__flags __lhs, __flags __rhs) {
0073   return static_cast<__flags>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs));
0074 }
0075 
0076 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_second(__flags __flags) {
0077   if ((__flags & __flags::__second) != __flags::__second)
0078     std::__throw_format_error("The supplied date time doesn't contain a second");
0079 }
0080 
0081 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_minute(__flags __flags) {
0082   if ((__flags & __flags::__minute) != __flags::__minute)
0083     std::__throw_format_error("The supplied date time doesn't contain a minute");
0084 }
0085 
0086 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_hour(__flags __flags) {
0087   if ((__flags & __flags::__hour) != __flags::__hour)
0088     std::__throw_format_error("The supplied date time doesn't contain an hour");
0089 }
0090 
0091 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_time(__flags __flags) {
0092   if ((__flags & __flags::__time) != __flags::__time)
0093     std::__throw_format_error("The supplied date time doesn't contain a time");
0094 }
0095 
0096 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_day(__flags __flags) {
0097   if ((__flags & __flags::__day) != __flags::__day)
0098     std::__throw_format_error("The supplied date time doesn't contain a day");
0099 }
0100 
0101 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_month(__flags __flags) {
0102   if ((__flags & __flags::__month) != __flags::__month)
0103     std::__throw_format_error("The supplied date time doesn't contain a month");
0104 }
0105 
0106 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_year(__flags __flags) {
0107   if ((__flags & __flags::__year) != __flags::__year)
0108     std::__throw_format_error("The supplied date time doesn't contain a year");
0109 }
0110 
0111 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date(__flags __flags) {
0112   if ((__flags & __flags::__date) != __flags::__date)
0113     std::__throw_format_error("The supplied date time doesn't contain a date");
0114 }
0115 
0116 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_or_duration(__flags __flags) {
0117   if (((__flags & __flags::__date) != __flags::__date) && ((__flags & __flags::__duration) != __flags::__duration))
0118     std::__throw_format_error("The supplied date time doesn't contain a date or duration");
0119 }
0120 
0121 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_time(__flags __flags) {
0122   if ((__flags & __flags::__date_time) != __flags::__date_time)
0123     std::__throw_format_error("The supplied date time doesn't contain a date and time");
0124 }
0125 
0126 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_weekday(__flags __flags) {
0127   if ((__flags & __flags::__weekday) != __flags::__weekday)
0128     std::__throw_format_error("The supplied date time doesn't contain a weekday");
0129 }
0130 
0131 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_duration(__flags __flags) {
0132   if ((__flags & __flags::__duration) != __flags::__duration)
0133     std::__throw_format_error("The supplied date time doesn't contain a duration");
0134 }
0135 
0136 _LIBCPP_HIDE_FROM_ABI constexpr void __validate_time_zone(__flags __flags) {
0137   if ((__flags & __flags::__time_zone) != __flags::__time_zone)
0138     std::__throw_format_error("The supplied date time doesn't contain a time zone");
0139 }
0140 
0141 template <class _CharT>
0142 class _LIBCPP_TEMPLATE_VIS __parser_chrono {
0143   using _ConstIterator _LIBCPP_NODEBUG = typename basic_format_parse_context<_CharT>::const_iterator;
0144 
0145 public:
0146   template <class _ParseContext>
0147   _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
0148   __parse(_ParseContext& __ctx, __fields __fields, __flags __flags) {
0149     _ConstIterator __begin = __parser_.__parse(__ctx, __fields);
0150     _ConstIterator __end   = __ctx.end();
0151     if (__begin == __end)
0152       return __begin;
0153 
0154     _ConstIterator __last = __parse_chrono_specs(__begin, __end, __flags);
0155     __chrono_specs_       = basic_string_view<_CharT>{__begin, __last};
0156 
0157     return __last;
0158   }
0159 
0160   __parser<_CharT> __parser_;
0161   basic_string_view<_CharT> __chrono_specs_;
0162 
0163 private:
0164   _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
0165   __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
0166     _LIBCPP_ASSERT_INTERNAL(__begin != __end,
0167                             "When called with an empty input the function will cause "
0168                             "undefined behavior by evaluating data not in the input");
0169 
0170     if (*__begin != _CharT('%') && *__begin != _CharT('}'))
0171       std::__throw_format_error("The format specifier expects a '%' or a '}'");
0172 
0173     do {
0174       switch (*__begin) {
0175       case _CharT('{'):
0176         std::__throw_format_error("The chrono specifiers contain a '{'");
0177 
0178       case _CharT('}'):
0179         return __begin;
0180 
0181       case _CharT('%'):
0182         __parse_conversion_spec(__begin, __end, __flags);
0183         [[fallthrough]];
0184 
0185       default:
0186         // All other literals
0187         ++__begin;
0188       }
0189 
0190     } while (__begin != __end && *__begin != _CharT('}'));
0191 
0192     return __begin;
0193   }
0194 
0195   /// \pre *__begin == '%'
0196   /// \post __begin points at the end parsed conversion-spec
0197   _LIBCPP_HIDE_FROM_ABI constexpr void
0198   __parse_conversion_spec(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
0199     ++__begin;
0200     if (__begin == __end)
0201       std::__throw_format_error("End of input while parsing a conversion specifier");
0202 
0203     switch (*__begin) {
0204     case _CharT('n'):
0205     case _CharT('t'):
0206     case _CharT('%'):
0207       break;
0208 
0209     case _CharT('S'):
0210       __format_spec::__validate_second(__flags);
0211       break;
0212 
0213     case _CharT('M'):
0214       __format_spec::__validate_minute(__flags);
0215       break;
0216 
0217     case _CharT('p'): // TODO FMT does the formater require an hour or a time?
0218     case _CharT('H'):
0219     case _CharT('I'):
0220       __parser_.__hour_ = true;
0221       __validate_hour(__flags);
0222       break;
0223 
0224     case _CharT('r'):
0225     case _CharT('R'):
0226     case _CharT('T'):
0227     case _CharT('X'):
0228       __parser_.__hour_ = true;
0229       __format_spec::__validate_time(__flags);
0230       break;
0231 
0232     case _CharT('d'):
0233     case _CharT('e'):
0234       __format_spec::__validate_day(__flags);
0235       break;
0236 
0237     case _CharT('b'):
0238     case _CharT('h'):
0239     case _CharT('B'):
0240       __parser_.__month_name_ = true;
0241       [[fallthrough]];
0242     case _CharT('m'):
0243       __format_spec::__validate_month(__flags);
0244       break;
0245 
0246     case _CharT('y'):
0247     case _CharT('C'):
0248     case _CharT('Y'):
0249       __format_spec::__validate_year(__flags);
0250       break;
0251 
0252     case _CharT('j'):
0253       __parser_.__day_of_year_ = true;
0254       __format_spec::__validate_date_or_duration(__flags);
0255       break;
0256 
0257     case _CharT('g'):
0258     case _CharT('G'):
0259     case _CharT('U'):
0260     case _CharT('V'):
0261     case _CharT('W'):
0262       __parser_.__week_of_year_ = true;
0263       [[fallthrough]];
0264     case _CharT('x'):
0265     case _CharT('D'):
0266     case _CharT('F'):
0267       __format_spec::__validate_date(__flags);
0268       break;
0269 
0270     case _CharT('c'):
0271       __format_spec::__validate_date_time(__flags);
0272       break;
0273 
0274     case _CharT('a'):
0275     case _CharT('A'):
0276       __parser_.__weekday_name_ = true;
0277       [[fallthrough]];
0278     case _CharT('u'):
0279     case _CharT('w'):
0280       __parser_.__weekday_ = true;
0281       __validate_weekday(__flags);
0282       __format_spec::__validate_weekday(__flags);
0283       break;
0284 
0285     case _CharT('q'):
0286     case _CharT('Q'):
0287       __format_spec::__validate_duration(__flags);
0288       break;
0289 
0290     case _CharT('E'):
0291       __parse_modifier_E(__begin, __end, __flags);
0292       break;
0293 
0294     case _CharT('O'):
0295       __parse_modifier_O(__begin, __end, __flags);
0296       break;
0297 
0298     case _CharT('z'):
0299     case _CharT('Z'):
0300       // Currently there's no time zone information. However some clocks have a
0301       // hard-coded "time zone", for these clocks the information can be used.
0302       // TODO FMT implement time zones.
0303       __format_spec::__validate_time_zone(__flags);
0304       break;
0305 
0306     default: // unknown type;
0307       std::__throw_format_error("The date time type specifier is invalid");
0308     }
0309   }
0310 
0311   /// \pre *__begin == 'E'
0312   /// \post __begin is incremented by one.
0313   _LIBCPP_HIDE_FROM_ABI constexpr void
0314   __parse_modifier_E(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
0315     ++__begin;
0316     if (__begin == __end)
0317       std::__throw_format_error("End of input while parsing the modifier E");
0318 
0319     switch (*__begin) {
0320     case _CharT('X'):
0321       __parser_.__hour_ = true;
0322       __format_spec::__validate_time(__flags);
0323       break;
0324 
0325     case _CharT('y'):
0326     case _CharT('C'):
0327     case _CharT('Y'):
0328       __format_spec::__validate_year(__flags);
0329       break;
0330 
0331     case _CharT('x'):
0332       __format_spec::__validate_date(__flags);
0333       break;
0334 
0335     case _CharT('c'):
0336       __format_spec::__validate_date_time(__flags);
0337       break;
0338 
0339     case _CharT('z'):
0340       // Currently there's no time zone information. However some clocks have a
0341       // hard-coded "time zone", for these clocks the information can be used.
0342       // TODO FMT implement time zones.
0343       __format_spec::__validate_time_zone(__flags);
0344       break;
0345 
0346     default:
0347       std::__throw_format_error("The date time type specifier for modifier E is invalid");
0348     }
0349   }
0350 
0351   /// \pre *__begin == 'O'
0352   /// \post __begin is incremented by one.
0353   _LIBCPP_HIDE_FROM_ABI constexpr void
0354   __parse_modifier_O(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
0355     ++__begin;
0356     if (__begin == __end)
0357       std::__throw_format_error("End of input while parsing the modifier O");
0358 
0359     switch (*__begin) {
0360     case _CharT('S'):
0361       __format_spec::__validate_second(__flags);
0362       break;
0363 
0364     case _CharT('M'):
0365       __format_spec::__validate_minute(__flags);
0366       break;
0367 
0368     case _CharT('I'):
0369     case _CharT('H'):
0370       __parser_.__hour_ = true;
0371       __format_spec::__validate_hour(__flags);
0372       break;
0373 
0374     case _CharT('d'):
0375     case _CharT('e'):
0376       __format_spec::__validate_day(__flags);
0377       break;
0378 
0379     case _CharT('m'):
0380       __format_spec::__validate_month(__flags);
0381       break;
0382 
0383     case _CharT('y'):
0384       __format_spec::__validate_year(__flags);
0385       break;
0386 
0387     case _CharT('U'):
0388     case _CharT('V'):
0389     case _CharT('W'):
0390       __parser_.__week_of_year_ = true;
0391       __format_spec::__validate_date(__flags);
0392       break;
0393 
0394     case _CharT('u'):
0395     case _CharT('w'):
0396       __parser_.__weekday_ = true;
0397       __format_spec::__validate_weekday(__flags);
0398       break;
0399 
0400     case _CharT('z'):
0401       // Currently there's no time zone information. However some clocks have a
0402       // hard-coded "time zone", for these clocks the information can be used.
0403       // TODO FMT implement time zones.
0404       __format_spec::__validate_time_zone(__flags);
0405       break;
0406 
0407     default:
0408       std::__throw_format_error("The date time type specifier for modifier O is invalid");
0409     }
0410   }
0411 };
0412 
0413 } // namespace __format_spec
0414 
0415 #  endif // _LIBCPP_STD_VER >= 20
0416 
0417 _LIBCPP_END_NAMESPACE_STD
0418 
0419 #endif // _LIBCPP_HAS_LOCALIZATION
0420 
0421 #endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H