22#ifndef FMT_SAFE_DURATION_CAST
23# define FMT_SAFE_DURATION_CAST 1
25#if FMT_SAFE_DURATION_CAST
33namespace safe_duration_cast {
35template <
typename To,
typename From,
39FMT_CONSTEXPR To lossless_integral_conversion(
const From from,
int& ec) {
43 static_assert(F::is_integer,
"From must be integral");
44 static_assert(T::is_integer,
"To must be integral");
47 if (F::digits <= T::digits) {
51 if (from < (T::min)() || from > (T::max)()) {
57 return static_cast<To
>(from);
64template <
typename To,
typename From,
68FMT_CONSTEXPR To lossless_integral_conversion(
const From from,
int& ec) {
72 static_assert(F::is_integer,
"From must be integral");
73 static_assert(T::is_integer,
"To must be integral");
75 if (detail::const_check(F::is_signed && !T::is_signed)) {
77 if (fmt::detail::is_negative(from)) {
82 if (F::digits > T::digits &&
83 from >
static_cast<From
>(detail::max_value<To>())) {
89 if (!F::is_signed && T::is_signed && F::digits >= T::digits &&
90 from >
static_cast<From
>(detail::max_value<To>())) {
94 return static_cast<To
>(from);
97template <
typename To,
typename From,
99FMT_CONSTEXPR To lossless_integral_conversion(
const From from,
int& ec) {
118template <
typename To,
typename From,
120FMT_CONSTEXPR To safe_float_conversion(
const From from,
int& ec) {
128 if (from >= T::lowest() && from <= (T::max)()) {
129 return static_cast<To
>(from);
137 return static_cast<To
>(from);
140template <
typename To,
typename From,
142FMT_CONSTEXPR To safe_float_conversion(
const From from,
int& ec) {
151template <
typename To,
typename FromRep,
typename FromPeriod,
163 static_assert(Factor::num > 0,
"num must be positive");
164 static_assert(Factor::den > 0,
"den must be positive");
170 using IntermediateRep =
172 decltype(Factor::num)>
::type;
175 IntermediateRep
count =
176 lossless_integral_conversion<IntermediateRep>(from.count(), ec);
179 if (detail::const_check(Factor::num != 1)) {
180 const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
191 count *= Factor::num;
194 if (detail::const_check(Factor::den != 1))
count /= Factor::den;
195 auto tocount = lossless_integral_conversion<typename To::rep>(
count, ec);
196 return ec ? To() : To(tocount);
202template <
typename To,
typename FromRep,
typename FromPeriod,
218 return To{from.count()};
226 static_assert(Factor::num > 0,
"num must be positive");
227 static_assert(Factor::den > 0,
"den must be positive");
233 using IntermediateRep =
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);
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);
285template <
typename T =
void>
struct null {};
297 auto end = facet.put(os, os,
' ', &time,
format, modifier);
303#if FMT_MSC_VER != 0 || \
304 (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
309 using code_unit = char32_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);
319 if (result != std::codecvt_base::ok)
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)));
353template <
typename OutputIt>
355 char format,
char modifier = 0) -> OutputIt {
357 return std::copy(str.begin(), str.end(), out);
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;
384 return fallback(localtime_s(&tm_, &time_));
387 bool fallback(
int res) {
return res == 0; }
391 using namespace fmt::detail;
394 return tm !=
nullptr;
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;
477template <
typename Char,
typename Duration>
478struct 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;
490 if (end != it) this->specs = {it, detail::to_unsigned(end - it)};
494 template <
typename FormatContext>
496 FormatContext& ctx) ->
decltype(ctx.out()) {
501 static constexpr Char default_specs[] = {
'%',
'Y',
'-',
'%',
'm',
'-',
502 '%',
'd',
' ',
'%',
'H',
':',
503 '%',
'M',
':',
'%',
'S'};
506template <
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;
518 specs = {it, detail::to_unsigned(end - it)};
522 template <
typename FormatContext>
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;
536 size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm);
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());
583template <
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);
772 template <
typename Char>
786template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
790template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
795template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
799template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
805template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
810 return static_cast<int>(
value);
812template <
typename T, FMT_ENABLE_IF(!std::is_
integral<T>::value)>
818 return static_cast<int>(
value);
821template <
typename T, FMT_ENABLE_IF(std::is_
integral<T>::value)>
823 return x %
static_cast<T>(y);
825template <
typename T, FMT_ENABLE_IF(std::is_
floating_po
int<T>::value)>
826inline T mod(
T x,
int y) {
832template <typename T, bool INTEGRAL = std::is_integral<T>::value>
841#if FMT_SAFE_DURATION_CAST
843template <
typename To,
typename FromRep,
typename FromPeriod>
846 To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
852template <
typename Rep,
typename Period,
858#if FMT_SAFE_DURATION_CAST
859 using CommonSecondsType =
861 const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
862 const auto d_as_whole_seconds =
863 fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
865 const auto diff = d_as_common - d_as_whole_seconds;
867 fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
870 auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
871 return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
875template <
typename Rep,
typename Period,
880 auto ms =
mod(d.
count() *
static_cast<common_type
>(Period::num) /
881 static_cast<common_type
>(Period::den) * 1000,
886template <
typename Char,
typename Rep,
typename OutputIt,
889 return write<Char>(out, val);
892template <
typename Char,
typename Rep,
typename OutputIt,
896 specs.precision = precision;
897 specs.type = precision > 0 ?
'f' :
'g';
898 return write<Char>(out, val, specs);
901template <
typename Char,
typename OutputIt>
906template <
typename OutputIt>
914template <
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);
929template <
typename FormatContext,
typename OutputIt,
typename Rep,
961#if FMT_SAFE_DURATION_CAST
964 s = fmt_safe_duration_cast<seconds>(tmpval);
966 s = std::chrono::duration_cast<seconds>(
1019 int num_digits = detail::count_digits(n);
1021 out = format_decimal<char_type>(
out, n, num_digits).end;
1086#if FMT_SAFE_DURATION_CAST
1090 auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{
val});
1097 write(ms.count(), 3);
1142 out = format_duration_unit<char_type, Period>(
out);
1148#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
1149using weekday = std::chrono::weekday;
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') {
1181 time.tm_wday =
static_cast<int>(wd.c_encoding());
1188template <
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};
1249 begin = detail::parse_align(begin, end, handler);
1250 if (begin == end)
return {begin, begin};
1251 begin = detail::parse_width(begin, end, handler);
1252 if (begin == end)
return {begin, begin};
1253 if (*begin ==
'.') {
1255 begin = detail::parse_precision(begin, end, handler);
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);
1272 &*range.begin, detail::to_unsigned(range.end - range.begin));
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();
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;
1298 detail::parse_chrono_format(begin, end, f);
T back_inserter(T... args)
FMT_CONSTEXPR const Char * parse_chrono_format(const Char *begin, const Char *end, Handler &&handler)
OutputIt copy_unit(string_view unit, OutputIt out, Char)
OutputIt format_duration_value(OutputIt out, Rep val, int)
FMT_MODULE_EXPORT_BEGIN std::tm localtime(std::time_t time)
std::chrono::duration< Rep, std::milli > get_milliseconds(std::chrono::duration< Rep, Period > d)
OutputIt format_duration_unit(OutputIt out)
std::tm gmtime(std::time_t time)
int to_nonnegative_int(T value, int upper)
FMT_BEGIN_DETAIL_NAMESPACE size_t strftime(char *str, size_t count, const char *format, const std::tm *time)
FMT_BEGIN_DETAIL_NAMESPACE FMT_CONSTEXPR const char * get_units()
constexpr auto end() const FMT_NOEXCEPT -> iterator
FMT_CONSTEXPR void check_arg_id(int)
typename basic_string_view< Char >::iterator iterator
FMT_CONSTEXPR auto next_arg_id() -> int
constexpr auto begin() const FMT_NOEXCEPT -> iterator
void reserve(size_t new_capacity)
void append(const ContiguousRange &range)
void resize(size_t count)
constexpr auto end() const -> iterator
constexpr auto begin() const -> iterator
auto size() const -> size_t
auto c_str() const -> const wchar_t *
constexpr weekday(unsigned wd) noexcept
constexpr unsigned c_encoding() const noexcept
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
#define FMT_ASSERT(condition, message)
#define FMT_END_DETAIL_NAMESPACE
#define FMT_MODULE_EXPORT_BEGIN
constexpr auto count() -> size_t
#define FMT_BEGIN_NAMESPACE
#define FMT_BEGIN_DETAIL_NAMESPACE
constexpr auto const_check(T value) -> T
#define FMT_ENABLE_IF(...)
FMT_CONSTEXPR auto to_unsigned(Int value) -> typename std::make_unsigned< Int >::type
typename std::conditional< B, T, F >::type conditional_t
#define FMT_END_NAMESPACE
#define FMT_MODULE_EXPORT_END
template FMT_API std::locale detail::locale_ref::get< std::locale >() const
auto write(OutputIt out, const std::tm &time, const std::locale &loc, char format, char modifier=0) -> OutputIt
auto do_write(const std::tm &time, const std::locale &loc, char format, char modifier) -> std::string
typename std::make_unsigned< T >::type type
FMT_CONSTEXPR void on_datetime(numeric_system)
FMT_CONSTEXPR void on_full_month()
FMT_CONSTEXPR void on_second(numeric_system)
FMT_CONSTEXPR void on_abbr_month()
FMT_CONSTEXPR void on_us_date()
FMT_CONSTEXPR void on_am_pm()
FMT_CONSTEXPR void on_dec0_weekday(numeric_system)
FMT_CONSTEXPR void on_abbr_weekday()
FMT_CONSTEXPR void on_utc_offset()
FMT_CONSTEXPR void on_iso_date()
FMT_CONSTEXPR void on_duration_unit()
FMT_CONSTEXPR void on_24_hour(numeric_system)
FMT_CONSTEXPR void on_12_hour(numeric_system)
FMT_CONSTEXPR void on_full_weekday()
FMT_CONSTEXPR void unsupported()
FMT_CONSTEXPR void on_duration_value()
FMT_CONSTEXPR void on_12_hour_time()
FMT_CONSTEXPR void on_loc_date(numeric_system)
FMT_CONSTEXPR void on_iso_time()
FMT_CONSTEXPR void on_dec1_weekday(numeric_system)
FMT_CONSTEXPR void on_24_hour_time()
FMT_CONSTEXPR void on_loc_time(numeric_system)
FMT_CONSTEXPR void on_minute(numeric_system)
FMT_CONSTEXPR void on_tz_name()