Several headers that should not be provided when localization or threads are disabled were not guarded. That works until one tries to build with modules and these headers get pulled in. Note that this could be cleaned up further into something more systematic, but this patch solves the immediate problems I ran into with the monolithic modulemap and doesn't create any new inconsistency that wasn't already there.
422 lines
12 KiB
C++
422 lines
12 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
|
|
#define _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
|
|
|
|
#include <__config>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
|
|
|
# include <__format/concepts.h>
|
|
# include <__format/format_error.h>
|
|
# include <__format/format_parse_context.h>
|
|
# include <__format/formatter_string.h>
|
|
# include <__format/parser_std_format_spec.h>
|
|
# include <string_view>
|
|
|
|
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
# endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
# if _LIBCPP_STD_VER >= 20
|
|
|
|
namespace __format_spec {
|
|
|
|
// By not placing this constant in the formatter class it's not duplicated for char and wchar_t
|
|
inline constexpr __fields __fields_chrono_fractional{
|
|
.__precision_ = true, .__locale_specific_form_ = true, .__type_ = false};
|
|
inline constexpr __fields __fields_chrono{.__locale_specific_form_ = true, .__type_ = false};
|
|
|
|
/// Flags available or required in a chrono type.
|
|
///
|
|
/// The caller of the chrono formatter lists the types it has available and the
|
|
/// validation tests whether the requested type spec (e.g. %M) is available in
|
|
/// the formatter.
|
|
/// When the type in the chrono-format-spec isn't present in the data a
|
|
/// \ref format_error is thrown.
|
|
enum class __flags {
|
|
__second = 0x1,
|
|
__minute = 0x2,
|
|
__hour = 0x4,
|
|
__time = __hour | __minute | __second,
|
|
|
|
__day = 0x8,
|
|
__month = 0x10,
|
|
__year = 0x20,
|
|
|
|
__weekday = 0x40,
|
|
|
|
__month_day = __day | __month,
|
|
__month_weekday = __weekday | __month,
|
|
__year_month = __month | __year,
|
|
__date = __day | __month | __year | __weekday,
|
|
|
|
__date_time = __date | __time,
|
|
|
|
__duration = 0x80 | __time,
|
|
|
|
__time_zone = 0x100,
|
|
|
|
__clock = __date_time | __time_zone
|
|
};
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr __flags operator&(__flags __lhs, __flags __rhs) {
|
|
return static_cast<__flags>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs));
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_second(__flags __flags) {
|
|
if ((__flags & __flags::__second) != __flags::__second)
|
|
std::__throw_format_error("The supplied date time doesn't contain a second");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_minute(__flags __flags) {
|
|
if ((__flags & __flags::__minute) != __flags::__minute)
|
|
std::__throw_format_error("The supplied date time doesn't contain a minute");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_hour(__flags __flags) {
|
|
if ((__flags & __flags::__hour) != __flags::__hour)
|
|
std::__throw_format_error("The supplied date time doesn't contain an hour");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time(__flags __flags) {
|
|
if ((__flags & __flags::__time) != __flags::__time)
|
|
std::__throw_format_error("The supplied date time doesn't contain a time");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_day(__flags __flags) {
|
|
if ((__flags & __flags::__day) != __flags::__day)
|
|
std::__throw_format_error("The supplied date time doesn't contain a day");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_month(__flags __flags) {
|
|
if ((__flags & __flags::__month) != __flags::__month)
|
|
std::__throw_format_error("The supplied date time doesn't contain a month");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_year(__flags __flags) {
|
|
if ((__flags & __flags::__year) != __flags::__year)
|
|
std::__throw_format_error("The supplied date time doesn't contain a year");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date(__flags __flags) {
|
|
if ((__flags & __flags::__date) != __flags::__date)
|
|
std::__throw_format_error("The supplied date time doesn't contain a date");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_or_duration(__flags __flags) {
|
|
if (((__flags & __flags::__date) != __flags::__date) && ((__flags & __flags::__duration) != __flags::__duration))
|
|
std::__throw_format_error("The supplied date time doesn't contain a date or duration");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_date_time(__flags __flags) {
|
|
if ((__flags & __flags::__date_time) != __flags::__date_time)
|
|
std::__throw_format_error("The supplied date time doesn't contain a date and time");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_weekday(__flags __flags) {
|
|
if ((__flags & __flags::__weekday) != __flags::__weekday)
|
|
std::__throw_format_error("The supplied date time doesn't contain a weekday");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_duration(__flags __flags) {
|
|
if ((__flags & __flags::__duration) != __flags::__duration)
|
|
std::__throw_format_error("The supplied date time doesn't contain a duration");
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void __validate_time_zone(__flags __flags) {
|
|
if ((__flags & __flags::__time_zone) != __flags::__time_zone)
|
|
std::__throw_format_error("The supplied date time doesn't contain a time zone");
|
|
}
|
|
|
|
template <class _CharT>
|
|
class _LIBCPP_TEMPLATE_VIS __parser_chrono {
|
|
using _ConstIterator = typename basic_format_parse_context<_CharT>::const_iterator;
|
|
|
|
public:
|
|
template <class _ParseContext>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator
|
|
__parse(_ParseContext& __ctx, __fields __fields, __flags __flags) {
|
|
_ConstIterator __begin = __parser_.__parse(__ctx, __fields);
|
|
_ConstIterator __end = __ctx.end();
|
|
if (__begin == __end)
|
|
return __begin;
|
|
|
|
_ConstIterator __last = __parse_chrono_specs(__begin, __end, __flags);
|
|
__chrono_specs_ = basic_string_view<_CharT>{__begin, __last};
|
|
|
|
return __last;
|
|
}
|
|
|
|
__parser<_CharT> __parser_;
|
|
basic_string_view<_CharT> __chrono_specs_;
|
|
|
|
private:
|
|
_LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
|
|
__parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
|
|
_LIBCPP_ASSERT_INTERNAL(__begin != __end,
|
|
"When called with an empty input the function will cause "
|
|
"undefined behavior by evaluating data not in the input");
|
|
|
|
if (*__begin != _CharT('%') && *__begin != _CharT('}'))
|
|
std::__throw_format_error("The format specifier expects a '%' or a '}'");
|
|
|
|
do {
|
|
switch (*__begin) {
|
|
case _CharT('{'):
|
|
std::__throw_format_error("The chrono specifiers contain a '{'");
|
|
|
|
case _CharT('}'):
|
|
return __begin;
|
|
|
|
case _CharT('%'):
|
|
__parse_conversion_spec(__begin, __end, __flags);
|
|
[[fallthrough]];
|
|
|
|
default:
|
|
// All other literals
|
|
++__begin;
|
|
}
|
|
|
|
} while (__begin != __end && *__begin != _CharT('}'));
|
|
|
|
return __begin;
|
|
}
|
|
|
|
/// \pre *__begin == '%'
|
|
/// \post __begin points at the end parsed conversion-spec
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void
|
|
__parse_conversion_spec(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
|
|
++__begin;
|
|
if (__begin == __end)
|
|
std::__throw_format_error("End of input while parsing a conversion specifier");
|
|
|
|
switch (*__begin) {
|
|
case _CharT('n'):
|
|
case _CharT('t'):
|
|
case _CharT('%'):
|
|
break;
|
|
|
|
case _CharT('S'):
|
|
__format_spec::__validate_second(__flags);
|
|
break;
|
|
|
|
case _CharT('M'):
|
|
__format_spec::__validate_minute(__flags);
|
|
break;
|
|
|
|
case _CharT('p'): // TODO FMT does the formater require an hour or a time?
|
|
case _CharT('H'):
|
|
case _CharT('I'):
|
|
__parser_.__hour_ = true;
|
|
__validate_hour(__flags);
|
|
break;
|
|
|
|
case _CharT('r'):
|
|
case _CharT('R'):
|
|
case _CharT('T'):
|
|
case _CharT('X'):
|
|
__parser_.__hour_ = true;
|
|
__format_spec::__validate_time(__flags);
|
|
break;
|
|
|
|
case _CharT('d'):
|
|
case _CharT('e'):
|
|
__format_spec::__validate_day(__flags);
|
|
break;
|
|
|
|
case _CharT('b'):
|
|
case _CharT('h'):
|
|
case _CharT('B'):
|
|
__parser_.__month_name_ = true;
|
|
[[fallthrough]];
|
|
case _CharT('m'):
|
|
__format_spec::__validate_month(__flags);
|
|
break;
|
|
|
|
case _CharT('y'):
|
|
case _CharT('C'):
|
|
case _CharT('Y'):
|
|
__format_spec::__validate_year(__flags);
|
|
break;
|
|
|
|
case _CharT('j'):
|
|
__parser_.__day_of_year_ = true;
|
|
__format_spec::__validate_date_or_duration(__flags);
|
|
break;
|
|
|
|
case _CharT('g'):
|
|
case _CharT('G'):
|
|
case _CharT('U'):
|
|
case _CharT('V'):
|
|
case _CharT('W'):
|
|
__parser_.__week_of_year_ = true;
|
|
[[fallthrough]];
|
|
case _CharT('x'):
|
|
case _CharT('D'):
|
|
case _CharT('F'):
|
|
__format_spec::__validate_date(__flags);
|
|
break;
|
|
|
|
case _CharT('c'):
|
|
__format_spec::__validate_date_time(__flags);
|
|
break;
|
|
|
|
case _CharT('a'):
|
|
case _CharT('A'):
|
|
__parser_.__weekday_name_ = true;
|
|
[[fallthrough]];
|
|
case _CharT('u'):
|
|
case _CharT('w'):
|
|
__parser_.__weekday_ = true;
|
|
__validate_weekday(__flags);
|
|
__format_spec::__validate_weekday(__flags);
|
|
break;
|
|
|
|
case _CharT('q'):
|
|
case _CharT('Q'):
|
|
__format_spec::__validate_duration(__flags);
|
|
break;
|
|
|
|
case _CharT('E'):
|
|
__parse_modifier_E(__begin, __end, __flags);
|
|
break;
|
|
|
|
case _CharT('O'):
|
|
__parse_modifier_O(__begin, __end, __flags);
|
|
break;
|
|
|
|
case _CharT('z'):
|
|
case _CharT('Z'):
|
|
// Currently there's no time zone information. However some clocks have a
|
|
// hard-coded "time zone", for these clocks the information can be used.
|
|
// TODO FMT implement time zones.
|
|
__format_spec::__validate_time_zone(__flags);
|
|
break;
|
|
|
|
default: // unknown type;
|
|
std::__throw_format_error("The date time type specifier is invalid");
|
|
}
|
|
}
|
|
|
|
/// \pre *__begin == 'E'
|
|
/// \post __begin is incremented by one.
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void
|
|
__parse_modifier_E(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
|
|
++__begin;
|
|
if (__begin == __end)
|
|
std::__throw_format_error("End of input while parsing the modifier E");
|
|
|
|
switch (*__begin) {
|
|
case _CharT('X'):
|
|
__parser_.__hour_ = true;
|
|
__format_spec::__validate_time(__flags);
|
|
break;
|
|
|
|
case _CharT('y'):
|
|
case _CharT('C'):
|
|
case _CharT('Y'):
|
|
__format_spec::__validate_year(__flags);
|
|
break;
|
|
|
|
case _CharT('x'):
|
|
__format_spec::__validate_date(__flags);
|
|
break;
|
|
|
|
case _CharT('c'):
|
|
__format_spec::__validate_date_time(__flags);
|
|
break;
|
|
|
|
case _CharT('z'):
|
|
// Currently there's no time zone information. However some clocks have a
|
|
// hard-coded "time zone", for these clocks the information can be used.
|
|
// TODO FMT implement time zones.
|
|
__format_spec::__validate_time_zone(__flags);
|
|
break;
|
|
|
|
default:
|
|
std::__throw_format_error("The date time type specifier for modifier E is invalid");
|
|
}
|
|
}
|
|
|
|
/// \pre *__begin == 'O'
|
|
/// \post __begin is incremented by one.
|
|
_LIBCPP_HIDE_FROM_ABI constexpr void
|
|
__parse_modifier_O(_ConstIterator& __begin, _ConstIterator __end, __flags __flags) {
|
|
++__begin;
|
|
if (__begin == __end)
|
|
std::__throw_format_error("End of input while parsing the modifier O");
|
|
|
|
switch (*__begin) {
|
|
case _CharT('S'):
|
|
__format_spec::__validate_second(__flags);
|
|
break;
|
|
|
|
case _CharT('M'):
|
|
__format_spec::__validate_minute(__flags);
|
|
break;
|
|
|
|
case _CharT('I'):
|
|
case _CharT('H'):
|
|
__parser_.__hour_ = true;
|
|
__format_spec::__validate_hour(__flags);
|
|
break;
|
|
|
|
case _CharT('d'):
|
|
case _CharT('e'):
|
|
__format_spec::__validate_day(__flags);
|
|
break;
|
|
|
|
case _CharT('m'):
|
|
__format_spec::__validate_month(__flags);
|
|
break;
|
|
|
|
case _CharT('y'):
|
|
__format_spec::__validate_year(__flags);
|
|
break;
|
|
|
|
case _CharT('U'):
|
|
case _CharT('V'):
|
|
case _CharT('W'):
|
|
__parser_.__week_of_year_ = true;
|
|
__format_spec::__validate_date(__flags);
|
|
break;
|
|
|
|
case _CharT('u'):
|
|
case _CharT('w'):
|
|
__parser_.__weekday_ = true;
|
|
__format_spec::__validate_weekday(__flags);
|
|
break;
|
|
|
|
case _CharT('z'):
|
|
// Currently there's no time zone information. However some clocks have a
|
|
// hard-coded "time zone", for these clocks the information can be used.
|
|
// TODO FMT implement time zones.
|
|
__format_spec::__validate_time_zone(__flags);
|
|
break;
|
|
|
|
default:
|
|
std::__throw_format_error("The date time type specifier for modifier O is invalid");
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace __format_spec
|
|
|
|
# endif // _LIBCPP_STD_VER >= 20
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // !defined(_LIBCPP_HAS_NO_LOCALIZATION)
|
|
|
|
#endif // _LIBCPP___CHRONO_PARSER_STD_FORMAT_SPEC_H
|