brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 8ecc19f Raw
422 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H11#define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H12 13#include <__config>14 15#if _LIBCPP_HAS_LOCALIZATION16 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_header26#  endif27 28_LIBCPP_BEGIN_NAMESPACE_STD29 30#  if _LIBCPP_STD_VER >= 2031 32namespace __format_spec {33 34// By not placing this constant in the formatter class it's not duplicated for char and wchar_t35inline 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 the42/// validation tests whether the requested type spec (e.g. %M) is available in43/// the formatter.44/// When the type in the chrono-format-spec isn't present in the data a45/// \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_zone70};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::iterator148  __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 _ConstIterator165  __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 literals187        ++__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-spec197  _LIBCPP_HIDE_FROM_ABI constexpr void198  __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 a301      // 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 void314  __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 a341      // 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 void354  __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 a402      // 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_spec414 415#  endif // _LIBCPP_STD_VER >= 20416 417_LIBCPP_END_NAMESPACE_STD418 419#endif // _LIBCPP_HAS_LOCALIZATION420 421#endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H422