22 #ifndef FMT_SAFE_DURATION_CAST 23 # define FMT_SAFE_DURATION_CAST 1 25 #if FMT_SAFE_DURATION_CAST 35 template <
typename To,
typename From,
41 using F = std::numeric_limits<From>;
42 using T = std::numeric_limits<To>;
47 if (F::digits <= T::digits) {
51 if (from < (T::min)() || from > (T::max)()) {
57 return static_cast<To
>(from);
64 template <
typename To,
typename From,
70 using F = std::numeric_limits<From>;
71 using T = std::numeric_limits<To>;
82 if (F::digits > T::digits &&
83 from > static_cast<From>(detail::max_value<To>())) {
90 from > static_cast<From>(detail::max_value<To>())) {
94 return static_cast<To
>(from);
97 template <
typename To,
typename From,
118 template <
typename To,
typename From,
122 using T = std::numeric_limits<To>;
123 static_assert(std::is_floating_point<From>::value,
"From must be floating");
124 static_assert(std::is_floating_point<To>::value,
"To must be floating");
128 if (from >= T::lowest() && from <= (T::max)()) {
129 return static_cast<To
>(from);
137 return static_cast<To
>(from);
140 template <
typename To,
typename From,
144 static_assert(std::is_floating_point<From>::value,
"From must be floating");
151 template <
typename To,
typename FromRep,
typename FromPeriod,
156 using From = std::chrono::duration<FromRep, FromPeriod>;
161 : std::ratio_divide<typename From::period, typename To::period> {};
163 static_assert(Factor::num > 0,
"num must be positive");
164 static_assert(Factor::den > 0,
"den must be positive");
170 using IntermediateRep =
171 typename std::common_type<
typename From::rep,
typename To::rep,
172 decltype(Factor::num)>
::type;
175 IntermediateRep
count =
176 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
180 const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
186 (std::numeric_limits<IntermediateRep>::min)() / Factor::num;
191 count *= Factor::num;
195 auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
196 return ec ? To() : To(tocount);
202 template <
typename To,
typename FromRep,
typename FromPeriod,
204 FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
207 using From = std::chrono::duration<FromRep, FromPeriod>;
211 return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
217 if (std::isinf(from.count())) {
218 return To{from.count()};
224 : std::ratio_divide<typename From::period, typename To::period> {};
226 static_assert(Factor::num > 0,
"num must be positive");
227 static_assert(Factor::den > 0,
"den must be positive");
233 using IntermediateRep =
234 typename std::common_type<
typename From::rep,
typename To::rep,
235 decltype(Factor::num)>
::type;
239 IntermediateRep
count =
240 safe_float_conversion<IntermediateRep>(from.count(), ec);
246 if (Factor::num != 1) {
247 constexpr
auto max1 = detail::max_value<IntermediateRep>() /
248 static_cast<IntermediateRep>(Factor::num);
253 constexpr
auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
254 static_cast<IntermediateRep
>(Factor::num);
259 count *=
static_cast<IntermediateRep
>(Factor::num);
263 if (Factor::den != 1) {
265 count /=
static_cast<common_t
>(Factor::den);
269 using ToRep =
typename To::rep;
271 const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
285 template <
typename T =
void>
struct null {};
292 char modifier) -> std::string {
293 auto&& os = std::ostringstream();
295 using iterator = std::ostreambuf_iterator<char>;
296 const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc);
297 auto end = facet.put(os, os,
' ', &
time,
format, modifier);
303 #if FMT_MSC_VER != 0 || \ 304 (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) 307 using code_unit = wchar_t;
309 using code_unit = char32_t;
311 auto&
f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
312 auto mb = std::mbstate_t();
313 const char* from_next =
nullptr;
314 code_unit* to_next =
nullptr;
315 constexpr
size_t buf_size = 32;
316 code_unit buf[buf_size] = {};
317 auto result =
f.in(mb, str.data(), str.data() + str.size(), from_next, buf,
318 buf + buf_size, to_next);
322 for (code_unit* p = buf; p != to_next; ++p) {
323 uint32_t c =
static_cast<uint32_t
>(*p);
324 if (
sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
327 if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
330 c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
333 str.push_back(static_cast<char>(c));
334 }
else if (c < 0x800) {
335 str.push_back(static_cast<char>(0xc0 | (c >> 6)));
336 str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
337 }
else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
338 str.push_back(static_cast<char>(0xe0 | (c >> 12)));
339 str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
340 str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
341 }
else if (c >= 0x10000 && c <= 0x10ffff) {
342 str.push_back(static_cast<char>(0xf0 | (c >> 18)));
343 str.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
344 str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
345 str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
353 template <
typename OutputIt>
354 auto write(OutputIt out,
const std::tm&
time,
const std::locale& loc,
355 char format,
char modifier = 0) -> OutputIt {
357 return std::copy(str.begin(), str.end(), out);
373 dispatcher(std::time_t t) : time_(t) {}
376 using namespace fmt::detail;
377 return handle(localtime_r(&time_, &tm_));
380 bool handle(std::tm* tm) {
return tm !=
nullptr; }
383 using namespace fmt::detail;
387 bool fallback(
int res) {
return res == 0; }
391 using namespace fmt::detail;
394 return tm !=
nullptr;
405 std::chrono::time_point<std::chrono::system_clock> time_point) {
406 return localtime(std::chrono::system_clock::to_time_t(time_point));
419 dispatcher(std::time_t t) : time_(t) {}
422 using namespace fmt::detail;
423 return handle(
gmtime_r(&time_, &tm_));
426 bool handle(std::tm* tm) {
return tm !=
nullptr; }
429 using namespace fmt::detail;
430 return fallback(
gmtime_s(&tm_, &time_));
433 bool fallback(
int res) {
return res == 0; }
439 return tm !=
nullptr;
450 std::chrono::time_point<std::chrono::system_clock> time_point) {
451 return gmtime(std::chrono::system_clock::to_time_t(time_point));
457 const std::tm*
time) {
463 return strftime(str, count, format, time);
467 const std::tm*
time) {
470 const std::tm*) =
nullptr;
471 wcsftime = std::wcsftime;
472 return wcsftime(str, count, format, time);
477 template <
typename Char,
typename Duration>
478 struct formatter<
std::chrono::time_point<std::chrono::system_clock, Duration>,
481 this->specs = {default_specs,
sizeof(default_specs) /
sizeof(Char)};
484 template <
typename ParseContext>
486 auto it = ctx.begin();
487 if (it != ctx.end() && *it ==
':') ++it;
489 while (end != ctx.end() && *end !=
'}') ++end;
494 template <
typename FormatContext>
495 auto format(std::chrono::time_point<std::chrono::system_clock> val,
496 FormatContext& ctx) -> decltype(ctx.out()) {
501 static constexpr Char default_specs[] = {
'%',
'Y',
'-',
'%',
'm',
'-',
502 '%',
'd',
' ',
'%',
'H',
':',
503 '%',
'M',
':',
'%',
'S'};
506 template <
typename Char,
typename Duration>
509 Char>::default_specs[];
512 template <
typename ParseContext>
514 auto it = ctx.begin();
515 if (it != ctx.end() && *it ==
':') ++it;
517 while (end != ctx.end() && *end !=
'}') ++end;
522 template <
typename FormatContext>
523 auto format(
const std::tm& tm, FormatContext& ctx)
const 524 -> decltype(ctx.out()) {
526 tm_format.
append(specs.begin(), specs.end());
530 tm_format.push_back(
' ');
531 tm_format.push_back(
'\0');
533 size_t start = buf.size();
535 size_t size = buf.capacity() - start;
538 buf.
resize(start + count);
541 const size_t MIN_GROWTH = 10;
542 buf.
reserve(buf.capacity() + (size > MIN_GROWTH ?
size : MIN_GROWTH));
545 return std::copy(buf.begin(), buf.end() - 1, ctx.out());
554 if (std::is_same<Period, std::atto>::value)
return "as";
555 if (std::is_same<Period, std::femto>::value)
return "fs";
556 if (std::is_same<Period, std::pico>::value)
return "ps";
557 if (std::is_same<Period, std::nano>::value)
return "ns";
558 if (std::is_same<Period, std::micro>::value)
return "µs";
559 if (std::is_same<Period, std::milli>::value)
return "ms";
560 if (std::is_same<Period, std::centi>::value)
return "cs";
561 if (std::is_same<Period, std::deci>::value)
return "ds";
562 if (std::is_same<Period, std::ratio<1>>::
value)
return "s";
563 if (std::is_same<Period, std::deca>::value)
return "das";
564 if (std::is_same<Period, std::hecto>::value)
return "hs";
565 if (std::is_same<Period, std::kilo>::value)
return "ks";
566 if (std::is_same<Period, std::mega>::value)
return "Ms";
567 if (std::is_same<Period, std::giga>::value)
return "Gs";
568 if (std::is_same<Period, std::tera>::value)
return "Ts";
569 if (std::is_same<Period, std::peta>::value)
return "Ps";
570 if (std::is_same<Period, std::exa>::value)
return "Es";
571 if (std::is_same<Period, std::ratio<60>>::
value)
return "m";
572 if (std::is_same<Period, std::ratio<3600>>::
value)
return "h";
583 template <
typename Char,
typename Handler>
595 if (begin !=
ptr) handler.on_text(begin,
ptr);
601 handler.on_text(
ptr - 1,
ptr);
604 const Char newline[] = {
'\n'};
605 handler.on_text(newline, newline + 1);
609 const Char tab[] = {
'\t'};
610 handler.on_text(tab, tab + 1);
615 handler.on_abbr_weekday();
618 handler.on_full_weekday();
628 handler.on_abbr_month();
631 handler.on_full_month();
657 handler.on_us_date();
660 handler.on_iso_date();
663 handler.on_12_hour_time();
666 handler.on_24_hour_time();
669 handler.on_iso_time();
675 handler.on_duration_value();
678 handler.on_duration_unit();
681 handler.on_utc_offset();
684 handler.on_tz_name();
736 if (begin !=
ptr) handler.on_text(begin,
ptr);
742 static_cast<Derived*
>(
this)->unsupported();
772 template <
typename Char>
786 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
790 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
795 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
799 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
805 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
810 return static_cast<int>(value);
812 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
815 std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
818 return static_cast<int>(value);
821 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
823 return x %
static_cast<T
>(
y);
825 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
826 inline T
mod(T x,
int y) {
827 return std::fmod(x, static_cast<T>(y));
832 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
841 #if FMT_SAFE_DURATION_CAST 843 template <
typename To,
typename FromRep,
typename FromPeriod>
852 template <
typename Rep,
typename Period,
855 std::chrono::duration<Rep, Period> d) {
858 #if FMT_SAFE_DURATION_CAST 859 using CommonSecondsType =
862 const auto d_as_whole_seconds =
865 const auto diff = d_as_common - d_as_whole_seconds;
870 auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
871 return std::chrono::duration_cast<std::chrono::milliseconds>(d -
s);
875 template <
typename Rep,
typename Period,
878 std::chrono::duration<Rep, Period>
d) {
880 auto ms =
mod(d.count() *
static_cast<common_type
>(Period::num) /
881 static_cast<common_type>(Period::den) * 1000,
883 return std::chrono::duration<Rep, std::milli>(
static_cast<Rep
>(ms));
886 template <
typename Char,
typename Rep,
typename OutputIt,
889 return write<Char>(out, val);
892 template <
typename Char,
typename Rep,
typename OutputIt,
897 specs.type = precision > 0 ?
'f' :
'g';
898 return write<Char>(out, val, specs);
901 template <
typename Char,
typename OutputIt>
906 template <
typename OutputIt>
914 template <
typename Char,
typename Period,
typename OutputIt>
916 if (
const char* unit = get_units<Period>())
919 out = write<Char>(out, Period::num);
922 out = write<Char>(out, Period::den);
929 template <
typename FormatContext,
typename OutputIt,
typename Rep,
935 bool localized =
false;
949 std::chrono::duration<Rep, Period> d)
961 #if FMT_SAFE_DURATION_CAST 963 auto tmpval = std::chrono::duration<rep, Period>(val);
966 s = std::chrono::duration_cast<
seconds>(
967 std::chrono::duration<rep, Period>(val));
989 Rep
hour()
const {
return static_cast<Rep
>(
mod((s.count() / 3600), 24)); }
992 Rep hour =
static_cast<Rep
>(
mod((s.count() / 3600), 12));
993 return hour <= 0 ? 12 : hour;
996 Rep
minute()
const {
return static_cast<Rep
>(
mod((s.count() / 60), 60)); }
997 Rep
second()
const {
return static_cast<Rep
>(
mod(s.count(), 60)); }
1000 auto time = std::tm();
1016 if (
isnan(value))
return write_nan();
1020 if (width > num_digits) out =
std::fill_n(out, width - num_digits,
'0');
1021 out = format_decimal<char_type>(out, n, num_digits).end;
1029 if (
isnan(val))
return write_nan();
1030 const auto& loc = localized ? context.locale().template get<std::locale>()
1031 : std::locale::classic();
1055 if (handle_nan_inf())
return;
1060 format_localized(
time,
'H',
'O');
1064 if (handle_nan_inf())
return;
1069 format_localized(
time,
'I',
'O');
1073 if (handle_nan_inf())
return;
1078 format_localized(
time,
'M',
'O');
1082 if (handle_nan_inf())
return;
1086 #if FMT_SAFE_DURATION_CAST 1088 using duration_rep = std::chrono::duration<rep, Period>;
1089 using duration_Rep = std::chrono::duration<Rep, Period>;
1092 auto tmpval = std::chrono::duration<Rep, Period>(val);
1095 if (ms != std::chrono::milliseconds(0)) {
1097 write(ms.count(), 3);
1103 format_localized(
time,
'S',
'O');
1107 if (handle_nan_inf())
return;
1108 format_localized(
time(),
'r');
1112 if (handle_nan_inf()) {
1126 if (handle_nan_inf())
return;
1131 if (handle_nan_inf())
return;
1132 format_localized(
time(),
'p');
1136 if (handle_nan_inf())
return;
1138 out = format_duration_value<char_type>(out, val, precision);
1142 out = format_duration_unit<char_type, Period>(out);
1148 #if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 1149 using weekday = std::chrono::weekday;
1157 weekday() =
default;
1159 : value(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
1167 bool localized =
false;
1171 auto begin = ctx.begin(), end = ctx.end();
1172 if (begin != end && *begin ==
'L') {
1180 auto time = std::tm();
1181 time.tm_wday =
static_cast<int>(wd.c_encoding());
1182 const auto& loc = localized ? ctx.locale().template get<std::locale>()
1183 : std::locale::classic();
1188 template <
typename Rep,
typename Period,
typename Char>
1196 bool localized =
false;
1200 struct spec_handler {
1221 f.specs.fill =
fill;
1226 f.precision = _precision;
1231 f.width_ref = make_arg_ref(arg_id);
1235 f.precision_ref = make_arg_ref(arg_id);
1240 struct parse_range {
1246 auto begin = ctx.
begin(), end = ctx.
end();
1247 if (begin == end || *begin ==
'}')
return {begin, begin};
1248 spec_handler handler{*
this, ctx, format_str};
1250 if (begin == end)
return {begin, begin};
1252 if (begin == end)
return {begin, begin};
1253 if (*begin ==
'.') {
1254 if (std::is_floating_point<Rep>::value)
1257 handler.on_error(
"precision not allowed for this argument type");
1259 if (begin != end && *begin ==
'L') {
1264 return {begin, end};
1269 -> decltype(ctx.begin()) {
1270 auto range = do_parse(ctx);
1276 template <
typename FormatContext>
1278 -> decltype(ctx.out()) {
1279 auto specs_copy = specs;
1280 auto precision_copy = precision;
1281 auto begin = format_str.
begin(), end = format_str.
end();
1285 auto out = std::back_inserter(buf);
1286 detail::handle_dynamic_spec<detail::width_checker>(specs_copy.width,
1288 detail::handle_dynamic_spec<detail::precision_checker>(precision_copy,
1289 precision_ref, ctx);
1290 if (begin == end || *begin ==
'}') {
1291 out = detail::format_duration_value<Char>(out, d.count(), precision_copy);
1292 detail::format_duration_unit<Char, Period>(out);
1294 detail::chrono_formatter<FormatContext, decltype(out), Rep, Period>
f(
1296 f.precision = precision_copy;
1297 f.localized = localized;
1308 #endif // FMT_CHRONO_H_
FMT_CONSTEXPR auto to_unsigned(Int value) -> typename std::make_unsigned< Int >::type
#define FMT_MODULE_EXPORT_END
#define FMT_ENABLE_IF(...)
FMT_CONSTEXPR void on_am_pm()
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int &ec)
constexpr weekday(unsigned wd) noexcept
OutputIt format_duration_value(OutputIt out, Rep val, int)
#define FMT_BEGIN_DETAIL_NAMESPACE
void reserve(size_t new_capacity)
#define FMT_END_DETAIL_NAMESPACE
FMT_CONSTEXPR void on_duration_value()
constexpr std::uintptr_t align(std::size_t alignment, std::uintptr_t ptr, std::size_t &space)
typename std::conditional< B, T, F >::type conditional_t
constexpr auto begin() const FMT_NOEXCEPT -> iterator
To safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from, int &ec)
span_CONFIG_SIZE_TYPE size_t
FMT_CONSTEXPR void on_tz_name()
FMT_CONSTEXPR void on_utc_offset()
FMT_BEGIN_DETAIL_NAMESPACE size_t strftime(char *str, size_t count, const char *format, const std::tm *time)
FMT_CONSTEXPR void on_12_hour_time()
std::tm gmtime(std::time_t time)
constexpr auto const_check(T value) -> T
auto c_str() const -> const wchar_t *
void append(const ContiguousRange &range)
typename std::make_unsigned< T >::type type
FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T &value) -> OutputIt
FMT_BEGIN_DETAIL_NAMESPACE FMT_CONSTEXPR const char * get_units()
FMT_CONSTEXPR void on_abbr_month()
FMT_CONSTEXPR void on_full_month()
constexpr auto is_utf8() -> bool
FMT_CONSTEXPR void on_iso_date()
FMT_CONSTEXPR auto parse_precision(const Char *begin, const Char *end, Handler &&handler) -> const Char *
#define FMT_END_NAMESPACE
basic_string_view< char > string_view
constexpr auto end() const FMT_NOEXCEPT -> iterator
FMT_CONSTEXPR void on_loc_date(numeric_system)
FMT_CONSTEXPR void on_second(numeric_system)
FMT_CONSTEXPR void on_24_hour(numeric_system)
OutputIt copy_unit(string_view unit, OutputIt out, Char)
std::chrono::duration< Rep, std::milli > get_milliseconds(std::chrono::duration< Rep, Period > d)
FMT_CONSTEXPR void on_duration_unit()
auto write(OutputIt out, const std::tm &time, const std::locale &loc, char format, char modifier=0) -> OutputIt
FMT_CONSTEXPR auto next_arg_id() -> int
OutputIterator copy(const RangeT &range, OutputIterator out)
FMT_CONSTEXPR void on_iso_time()
auto size() const -> size_t
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
constexpr auto count() -> size_t
constexpr auto begin() const -> iterator
FMT_CONSTEXPR void on_abbr_weekday()
FMT_CONSTEXPR void on_24_hour_time()
FMT_MODULE_EXPORT_BEGIN std::tm localtime(std::time_t time)
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
OutputIt format_duration_unit(OutputIt out)
FMT_CONSTEXPR void on_full_weekday()
FMT_CONSTEXPR void on_minute(numeric_system)
FMT_CONSTEXPR void unsupported()
FMT_CONSTEXPR void on_12_hour(numeric_system)
FMT_CONSTEXPR To safe_float_conversion(const From from, int &ec)
FMT_CONSTEXPR void on_loc_time(numeric_system)
FMT_CONSTEXPR const Char * parse_chrono_format(const Char *begin, const Char *end, Handler &&handler)
int to_nonnegative_int(T value, int upper)
FMT_CONSTEXPR auto parse_width(const Char *begin, const Char *end, Handler &&handler) -> const Char *
auto do_write(const std::tm &time, const std::locale &loc, char format, char modifier) -> std::string
constexpr auto end() const -> iterator
constexpr unsigned c_encoding() const noexcept
To fmt_safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from)
void resize(size_t count)
span_constexpr std::size_t size(span< T, Extent > const &spn)
FMT_CONSTEXPR void on_datetime(numeric_system)
#define FMT_ASSERT(condition, message)
#define FMT_BEGIN_NAMESPACE
FMT_CONSTEXPR void check_arg_id(int)
#define FMT_MODULE_EXPORT_BEGIN
FMT_CONSTEXPR auto parse_align(const Char *begin, const Char *end, Handler &&handler) -> const Char *
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
FMT_CONSTEXPR void on_us_date()