Scippy

SoPlex

Sequential object-oriented simPlex

chrono.h
Go to the documentation of this file.
1 // Formatting library for C++ - chrono support
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 
8 #ifndef FMT_CHRONO_H_
9 #define FMT_CHRONO_H_
10 
11 #include "format.h"
12 #include "locale.h"
13 
14 #include <chrono>
15 #include <ctime>
16 #include <locale>
17 #include <sstream>
18 
20 
21 // Enable safe chrono durations, unless explicitly disabled.
22 #ifndef FMT_SAFE_DURATION_CAST
23 # define FMT_SAFE_DURATION_CAST 1
24 #endif
25 #if FMT_SAFE_DURATION_CAST
26 
27 // For conversion between std::chrono::durations without undefined
28 // behaviour or erroneous results.
29 // This is a stripped down version of duration_cast, for inclusion in fmt.
30 // See https://github.com/pauldreik/safe_duration_cast
31 //
32 // Copyright Paul Dreik 2019
33 namespace safe_duration_cast {
34 
35 template <typename To, typename From,
36  FMT_ENABLE_IF(!std::is_same<From, To>::value &&
37  std::numeric_limits<From>::is_signed ==
38  std::numeric_limits<To>::is_signed)>
39 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
40  ec = 0;
41  using F = std::numeric_limits<From>;
42  using T = std::numeric_limits<To>;
43  static_assert(F::is_integer, "From must be integral");
44  static_assert(T::is_integer, "To must be integral");
45 
46  // A and B are both signed, or both unsigned.
47  if (F::digits <= T::digits) {
48  // From fits in To without any problem.
49  } else {
50  // From does not always fit in To, resort to a dynamic check.
51  if (from < T::min() || from > T::max()) {
52  // outside range.
53  ec = 1;
54  return {};
55  }
56  }
57  return static_cast<To>(from);
58 }
59 
60 /**
61  * converts From to To, without loss. If the dynamic value of from
62  * can't be converted to To without loss, ec is set.
63  */
64 template <typename To, typename From,
65  FMT_ENABLE_IF(!std::is_same<From, To>::value &&
66  std::numeric_limits<From>::is_signed !=
67  std::numeric_limits<To>::is_signed)>
68 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
69  ec = 0;
70  using F = std::numeric_limits<From>;
71  using T = std::numeric_limits<To>;
72  static_assert(F::is_integer, "From must be integral");
73  static_assert(T::is_integer, "To must be integral");
74 
75  if (F::is_signed && !T::is_signed) {
76  // From may be negative, not allowed!
77  if (fmt::internal::is_negative(from)) {
78  ec = 1;
79  return {};
80  }
81 
82  // From is positive. Can it always fit in To?
83  if (F::digits <= T::digits) {
84  // yes, From always fits in To.
85  } else {
86  // from may not fit in To, we have to do a dynamic check
87  if (from > static_cast<From>(T::max())) {
88  ec = 1;
89  return {};
90  }
91  }
92  }
93 
94  if (!F::is_signed && T::is_signed) {
95  // can from be held in To?
96  if (F::digits < T::digits) {
97  // yes, From always fits in To.
98  } else {
99  // from may not fit in To, we have to do a dynamic check
100  if (from > static_cast<From>(T::max())) {
101  // outside range.
102  ec = 1;
103  return {};
104  }
105  }
106  }
107 
108  // reaching here means all is ok for lossless conversion.
109  return static_cast<To>(from);
110 
111 } // function
112 
113 template <typename To, typename From,
114  FMT_ENABLE_IF(std::is_same<From, To>::value)>
115 FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
116  ec = 0;
117  return from;
118 } // function
119 
120 // clang-format off
121 /**
122  * converts From to To if possible, otherwise ec is set.
123  *
124  * input | output
125  * ---------------------------------|---------------
126  * NaN | NaN
127  * Inf | Inf
128  * normal, fits in output | converted (possibly lossy)
129  * normal, does not fit in output | ec is set
130  * subnormal | best effort
131  * -Inf | -Inf
132  */
133 // clang-format on
134 template <typename To, typename From,
135  FMT_ENABLE_IF(!std::is_same<From, To>::value)>
136 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
137  ec = 0;
138  using T = std::numeric_limits<To>;
139  static_assert(std::is_floating_point<From>::value, "From must be floating");
140  static_assert(std::is_floating_point<To>::value, "To must be floating");
141 
142  // catch the only happy case
143  if (std::isfinite(from)) {
144  if (from >= T::lowest() && from <= T::max()) {
145  return static_cast<To>(from);
146  }
147  // not within range.
148  ec = 1;
149  return {};
150  }
151 
152  // nan and inf will be preserved
153  return static_cast<To>(from);
154 } // function
155 
156 template <typename To, typename From,
157  FMT_ENABLE_IF(std::is_same<From, To>::value)>
158 FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
159  ec = 0;
160  static_assert(std::is_floating_point<From>::value, "From must be floating");
161  return from;
162 }
163 
164 /**
165  * safe duration cast between integral durations
166  */
167 template <typename To, typename FromRep, typename FromPeriod,
168  FMT_ENABLE_IF(std::is_integral<FromRep>::value),
169  FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
170 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
171  int& ec) {
172  using From = std::chrono::duration<FromRep, FromPeriod>;
173  ec = 0;
174  // the basic idea is that we need to convert from count() in the from type
175  // to count() in the To type, by multiplying it with this:
176  struct Factor
177  : std::ratio_divide<typename From::period, typename To::period> {};
178 
179  static_assert(Factor::num > 0, "num must be positive");
180  static_assert(Factor::den > 0, "den must be positive");
181 
182  // the conversion is like this: multiply from.count() with Factor::num
183  // /Factor::den and convert it to To::rep, all this without
184  // overflow/underflow. let's start by finding a suitable type that can hold
185  // both To, From and Factor::num
186  using IntermediateRep =
187  typename std::common_type<typename From::rep, typename To::rep,
188  decltype(Factor::num)>::type;
189 
190  // safe conversion to IntermediateRep
191  IntermediateRep count =
192  lossless_integral_conversion<IntermediateRep>(from.count(), ec);
193  if (ec) {
194  return {};
195  }
196  // multiply with Factor::num without overflow or underflow
197  if (Factor::num != 1) {
198  const auto max1 = internal::max_value<IntermediateRep>() / Factor::num;
199  if (count > max1) {
200  ec = 1;
201  return {};
202  }
203  const auto min1 = std::numeric_limits<IntermediateRep>::min() / Factor::num;
204  if (count < min1) {
205  ec = 1;
206  return {};
207  }
208  count *= Factor::num;
209  }
210 
211  // this can't go wrong, right? den>0 is checked earlier.
212  if (Factor::den != 1) {
213  count /= Factor::den;
214  }
215  // convert to the to type, safely
216  using ToRep = typename To::rep;
217  const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
218  if (ec) {
219  return {};
220  }
221  return To{tocount};
222 }
223 
224 /**
225  * safe duration_cast between floating point durations
226  */
227 template <typename To, typename FromRep, typename FromPeriod,
228  FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
229  FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
230 To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
231  int& ec) {
232  using From = std::chrono::duration<FromRep, FromPeriod>;
233  ec = 0;
234  if (std::isnan(from.count())) {
235  // nan in, gives nan out. easy.
236  return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
237  }
238  // maybe we should also check if from is denormal, and decide what to do about
239  // it.
240 
241  // +-inf should be preserved.
242  if (std::isinf(from.count())) {
243  return To{from.count()};
244  }
245 
246  // the basic idea is that we need to convert from count() in the from type
247  // to count() in the To type, by multiplying it with this:
248  struct Factor
249  : std::ratio_divide<typename From::period, typename To::period> {};
250 
251  static_assert(Factor::num > 0, "num must be positive");
252  static_assert(Factor::den > 0, "den must be positive");
253 
254  // the conversion is like this: multiply from.count() with Factor::num
255  // /Factor::den and convert it to To::rep, all this without
256  // overflow/underflow. let's start by finding a suitable type that can hold
257  // both To, From and Factor::num
258  using IntermediateRep =
259  typename std::common_type<typename From::rep, typename To::rep,
260  decltype(Factor::num)>::type;
261 
262  // force conversion of From::rep -> IntermediateRep to be safe,
263  // even if it will never happen be narrowing in this context.
264  IntermediateRep count =
265  safe_float_conversion<IntermediateRep>(from.count(), ec);
266  if (ec) {
267  return {};
268  }
269 
270  // multiply with Factor::num without overflow or underflow
271  if (Factor::num != 1) {
272  constexpr auto max1 = internal::max_value<IntermediateRep>() /
273  static_cast<IntermediateRep>(Factor::num);
274  if (count > max1) {
275  ec = 1;
276  return {};
277  }
278  constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
279  static_cast<IntermediateRep>(Factor::num);
280  if (count < min1) {
281  ec = 1;
282  return {};
283  }
284  count *= static_cast<IntermediateRep>(Factor::num);
285  }
286 
287  // this can't go wrong, right? den>0 is checked earlier.
288  if (Factor::den != 1) {
289  using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
290  count /= static_cast<common_t>(Factor::den);
291  }
292 
293  // convert to the to type, safely
294  using ToRep = typename To::rep;
295 
296  const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
297  if (ec) {
298  return {};
299  }
300  return To{tocount};
301 }
302 } // namespace safe_duration_cast
303 #endif
304 
305 // Prevents expansion of a preceding token as a function-style macro.
306 // Usage: f FMT_NOMACRO()
307 #define FMT_NOMACRO
308 
309 namespace internal {
310 inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
311 inline null<> localtime_s(...) { return null<>(); }
312 inline null<> gmtime_r(...) { return null<>(); }
313 inline null<> gmtime_s(...) { return null<>(); }
314 } // namespace internal
315 
316 // Thread-safe replacement for std::localtime
317 inline std::tm localtime(std::time_t time) {
318  struct dispatcher {
319  std::time_t time_;
320  std::tm tm_;
321 
322  dispatcher(std::time_t t) : time_(t) {}
323 
324  bool run() {
325  using namespace fmt::internal;
326  return handle(localtime_r(&time_, &tm_));
327  }
328 
329  bool handle(std::tm* tm) { return tm != nullptr; }
330 
331  bool handle(internal::null<>) {
332  using namespace fmt::internal;
333  return fallback(localtime_s(&tm_, &time_));
334  }
335 
336  bool fallback(int res) { return res == 0; }
337 
338 #if !FMT_MSC_VER
339  bool fallback(internal::null<>) {
340  using namespace fmt::internal;
341  std::tm* tm = std::localtime(&time_);
342  if (tm) tm_ = *tm;
343  return tm != nullptr;
344  }
345 #endif
346  };
347  dispatcher lt(time);
348  // Too big time values may be unsupported.
349  if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
350  return lt.tm_;
351 }
352 
353 // Thread-safe replacement for std::gmtime
354 inline std::tm gmtime(std::time_t time) {
355  struct dispatcher {
356  std::time_t time_;
357  std::tm tm_;
358 
359  dispatcher(std::time_t t) : time_(t) {}
360 
361  bool run() {
362  using namespace fmt::internal;
363  return handle(gmtime_r(&time_, &tm_));
364  }
365 
366  bool handle(std::tm* tm) { return tm != nullptr; }
367 
368  bool handle(internal::null<>) {
369  using namespace fmt::internal;
370  return fallback(gmtime_s(&tm_, &time_));
371  }
372 
373  bool fallback(int res) { return res == 0; }
374 
375 #if !FMT_MSC_VER
376  bool fallback(internal::null<>) {
377  std::tm* tm = std::gmtime(&time_);
378  if (tm) tm_ = *tm;
379  return tm != nullptr;
380  }
381 #endif
382  };
383  dispatcher gt(time);
384  // Too big time values may be unsupported.
385  if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
386  return gt.tm_;
387 }
388 
389 namespace internal {
390 inline std::size_t strftime(char* str, std::size_t count, const char* format,
391  const std::tm* time) {
392  return std::strftime(str, count, format, time);
393 }
394 
395 inline std::size_t strftime(wchar_t* str, std::size_t count,
396  const wchar_t* format, const std::tm* time) {
397  return std::wcsftime(str, count, format, time);
398 }
399 } // namespace internal
400 
401 template <typename Char> struct formatter<std::tm, Char> {
402  template <typename ParseContext>
403  auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
404  auto it = ctx.begin();
405  if (it != ctx.end() && *it == ':') ++it;
406  auto end = it;
407  while (end != ctx.end() && *end != '}') ++end;
408  tm_format.reserve(internal::to_unsigned(end - it + 1));
409  tm_format.append(it, end);
410  tm_format.push_back('\0');
411  return end;
412  }
413 
414  template <typename FormatContext>
415  auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
417  std::size_t start = buf.size();
418  for (;;) {
419  std::size_t size = buf.capacity() - start;
420  std::size_t count =
421  internal::strftime(&buf[start], size, &tm_format[0], &tm);
422  if (count != 0) {
423  buf.resize(start + count);
424  break;
425  }
426  if (size >= tm_format.size() * 256) {
427  // If the buffer is 256 times larger than the format string, assume
428  // that `strftime` gives an empty result. There doesn't seem to be a
429  // better way to distinguish the two cases:
430  // https://github.com/fmtlib/fmt/issues/367
431  break;
432  }
433  const std::size_t MIN_GROWTH = 10;
434  buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
435  }
436  return std::copy(buf.begin(), buf.end(), ctx.out());
437  }
438 
440 };
441 
442 namespace internal {
443 template <typename Period> FMT_CONSTEXPR const char* get_units() {
444  return nullptr;
445 }
446 template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
447 template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
448 template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
449 template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
450 template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
451 template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
452 template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
453 template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
454 template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
455 template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
456 template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
457 template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
458 template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
459 template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
460 template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
461 template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
462 template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
463 template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
464  return "m";
465 }
466 template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
467  return "h";
468 }
469 
470 enum class numeric_system {
471  standard,
472  // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
474 };
475 
476 // Parses a put_time-like format string and invokes handler actions.
477 template <typename Char, typename Handler>
478 FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
479  const Char* end,
480  Handler&& handler) {
481  auto ptr = begin;
482  while (ptr != end) {
483  auto c = *ptr;
484  if (c == '}') break;
485  if (c != '%') {
486  ++ptr;
487  continue;
488  }
489  if (begin != ptr) handler.on_text(begin, ptr);
490  ++ptr; // consume '%'
491  if (ptr == end) FMT_THROW(format_error("invalid format"));
492  c = *ptr++;
493  switch (c) {
494  case '%':
495  handler.on_text(ptr - 1, ptr);
496  break;
497  case 'n': {
498  const char newline[] = "\n";
499  handler.on_text(newline, newline + 1);
500  break;
501  }
502  case 't': {
503  const char tab[] = "\t";
504  handler.on_text(tab, tab + 1);
505  break;
506  }
507  // Day of the week:
508  case 'a':
509  handler.on_abbr_weekday();
510  break;
511  case 'A':
512  handler.on_full_weekday();
513  break;
514  case 'w':
515  handler.on_dec0_weekday(numeric_system::standard);
516  break;
517  case 'u':
518  handler.on_dec1_weekday(numeric_system::standard);
519  break;
520  // Month:
521  case 'b':
522  handler.on_abbr_month();
523  break;
524  case 'B':
525  handler.on_full_month();
526  break;
527  // Hour, minute, second:
528  case 'H':
529  handler.on_24_hour(numeric_system::standard);
530  break;
531  case 'I':
532  handler.on_12_hour(numeric_system::standard);
533  break;
534  case 'M':
535  handler.on_minute(numeric_system::standard);
536  break;
537  case 'S':
538  handler.on_second(numeric_system::standard);
539  break;
540  // Other:
541  case 'c':
542  handler.on_datetime(numeric_system::standard);
543  break;
544  case 'x':
545  handler.on_loc_date(numeric_system::standard);
546  break;
547  case 'X':
548  handler.on_loc_time(numeric_system::standard);
549  break;
550  case 'D':
551  handler.on_us_date();
552  break;
553  case 'F':
554  handler.on_iso_date();
555  break;
556  case 'r':
557  handler.on_12_hour_time();
558  break;
559  case 'R':
560  handler.on_24_hour_time();
561  break;
562  case 'T':
563  handler.on_iso_time();
564  break;
565  case 'p':
566  handler.on_am_pm();
567  break;
568  case 'Q':
569  handler.on_duration_value();
570  break;
571  case 'q':
572  handler.on_duration_unit();
573  break;
574  case 'z':
575  handler.on_utc_offset();
576  break;
577  case 'Z':
578  handler.on_tz_name();
579  break;
580  // Alternative representation:
581  case 'E': {
582  if (ptr == end) FMT_THROW(format_error("invalid format"));
583  c = *ptr++;
584  switch (c) {
585  case 'c':
586  handler.on_datetime(numeric_system::alternative);
587  break;
588  case 'x':
589  handler.on_loc_date(numeric_system::alternative);
590  break;
591  case 'X':
592  handler.on_loc_time(numeric_system::alternative);
593  break;
594  default:
595  FMT_THROW(format_error("invalid format"));
596  }
597  break;
598  }
599  case 'O':
600  if (ptr == end) FMT_THROW(format_error("invalid format"));
601  c = *ptr++;
602  switch (c) {
603  case 'w':
604  handler.on_dec0_weekday(numeric_system::alternative);
605  break;
606  case 'u':
607  handler.on_dec1_weekday(numeric_system::alternative);
608  break;
609  case 'H':
610  handler.on_24_hour(numeric_system::alternative);
611  break;
612  case 'I':
613  handler.on_12_hour(numeric_system::alternative);
614  break;
615  case 'M':
616  handler.on_minute(numeric_system::alternative);
617  break;
618  case 'S':
619  handler.on_second(numeric_system::alternative);
620  break;
621  default:
622  FMT_THROW(format_error("invalid format"));
623  }
624  break;
625  default:
626  FMT_THROW(format_error("invalid format"));
627  }
628  begin = ptr;
629  }
630  if (begin != ptr) handler.on_text(begin, ptr);
631  return ptr;
632 }
633 
636 
637  template <typename Char> void on_text(const Char*, const Char*) {}
638  FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
639  FMT_NORETURN void on_full_weekday() { report_no_date(); }
640  FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
641  FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
642  FMT_NORETURN void on_abbr_month() { report_no_date(); }
643  FMT_NORETURN void on_full_month() { report_no_date(); }
648  FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
649  FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
650  FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
651  FMT_NORETURN void on_us_date() { report_no_date(); }
652  FMT_NORETURN void on_iso_date() { report_no_date(); }
653  void on_12_hour_time() {}
654  void on_24_hour_time() {}
655  void on_iso_time() {}
656  void on_am_pm() {}
659  FMT_NORETURN void on_utc_offset() { report_no_date(); }
660  FMT_NORETURN void on_tz_name() { report_no_date(); }
661 };
662 
663 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
664 inline bool isnan(T) {
665  return false;
666 }
667 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
668 inline bool isnan(T value) {
669  return std::isnan(value);
670 }
671 
672 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
673 inline bool isfinite(T) {
674  return true;
675 }
676 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
677 inline bool isfinite(T value) {
678  return std::isfinite(value);
679 }
680 
681 // Converts value to int and checks that it's in the range [0, upper).
682 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
683 inline int to_nonnegative_int(T value, int upper) {
684  FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
685  (void)upper;
686  return static_cast<int>(value);
687 }
688 template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
689 inline int to_nonnegative_int(T value, int upper) {
690  FMT_ASSERT(
691  std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
692  "invalid value");
693  (void)upper;
694  return static_cast<int>(value);
695 }
696 
697 template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
698 inline T mod(T x, int y) {
699  return x % static_cast<T>(y);
700 }
701 template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
702 inline T mod(T x, int y) {
703  return std::fmod(x, static_cast<T>(y));
704 }
705 
706 // If T is an integral type, maps T to its unsigned counterpart, otherwise
707 // leaves it unchanged (unlike std::make_unsigned).
708 template <typename T, bool INTEGRAL = std::is_integral<T>::value>
710  using type = T;
711 };
712 
713 template <typename T> struct make_unsigned_or_unchanged<T, true> {
715 };
716 
717 #if FMT_SAFE_DURATION_CAST
718 // throwing version of safe_duration_cast
719 template <typename To, typename FromRep, typename FromPeriod>
720 To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) {
721  int ec;
722  To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
723  if (ec) FMT_THROW(format_error("cannot format duration"));
724  return to;
725 }
726 #endif
727 
728 template <typename Rep, typename Period,
729  FMT_ENABLE_IF(std::is_integral<Rep>::value)>
730 inline std::chrono::duration<Rep, std::milli> get_milliseconds(
731  std::chrono::duration<Rep, Period> d) {
732  // this may overflow and/or the result may not fit in the
733  // target type.
734 #if FMT_SAFE_DURATION_CAST
735  using CommonSecondsType =
737  const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
738  const auto d_as_whole_seconds =
739  fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
740  // this conversion should be nonproblematic
741  const auto diff = d_as_common - d_as_whole_seconds;
742  const auto ms =
743  fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
744  return ms;
745 #else
746  auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
747  return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
748 #endif
749 }
750 
751 template <typename Rep, typename Period,
752  FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
753 inline std::chrono::duration<Rep, std::milli> get_milliseconds(
754  std::chrono::duration<Rep, Period> d) {
755  using common_type = typename std::common_type<Rep, std::intmax_t>::type;
756  auto ms = mod(d.count() * static_cast<common_type>(Period::num) /
757  static_cast<common_type>(Period::den) * 1000,
758  1000);
759  return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
760 }
761 
762 template <typename Rep, typename OutputIt>
763 OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
764  if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
765  return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
766  val);
767 }
768 
769 template <typename Period, typename OutputIt>
770 static OutputIt format_chrono_duration_unit(OutputIt out) {
771  if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
772  if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
773  return format_to(out, "[{}/{}]s", Period::num, Period::den);
774 }
775 
776 template <typename FormatContext, typename OutputIt, typename Rep,
777  typename Period>
779  FormatContext& context;
780  OutputIt out;
782  // rep is unsigned to avoid overflow.
783  using rep =
784  conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
787  using seconds = std::chrono::duration<rep>;
789  using milliseconds = std::chrono::duration<rep, std::milli>;
790  bool negative;
791 
793 
794  explicit chrono_formatter(FormatContext& ctx, OutputIt o,
795  std::chrono::duration<Rep, Period> d)
796  : context(ctx),
797  out(o),
798  val(static_cast<rep>(d.count())),
799  negative(false) {
800  if (d.count() < 0) {
801  val = 0 - val;
802  negative = true;
803  }
804 
805  // this may overflow and/or the result may not fit in the
806  // target type.
807 #if FMT_SAFE_DURATION_CAST
808  // might need checked conversion (rep!=Rep)
809  auto tmpval = std::chrono::duration<rep, Period>(val);
810  s = fmt_safe_duration_cast<seconds>(tmpval);
811 #else
812  s = std::chrono::duration_cast<seconds>(
813  std::chrono::duration<rep, Period>(val));
814 #endif
815  }
816 
817  // returns true if nan or inf, writes to out.
818  bool handle_nan_inf() {
819  if (isfinite(val)) {
820  return false;
821  }
822  if (isnan(val)) {
823  write_nan();
824  return true;
825  }
826  // must be +-inf
827  if (val > 0) {
828  write_pinf();
829  } else {
830  write_ninf();
831  }
832  return true;
833  }
834 
835  Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); }
836 
837  Rep hour12() const {
838  Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
839  return hour <= 0 ? 12 : hour;
840  }
841 
842  Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); }
843  Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); }
844 
845  std::tm time() const {
846  auto time = std::tm();
847  time.tm_hour = to_nonnegative_int(hour(), 24);
848  time.tm_min = to_nonnegative_int(minute(), 60);
849  time.tm_sec = to_nonnegative_int(second(), 60);
850  return time;
851  }
852 
853  void write_sign() {
854  if (negative) {
855  *out++ = '-';
856  negative = false;
857  }
858  }
859 
860  void write(Rep value, int width) {
861  write_sign();
862  if (isnan(value)) return write_nan();
864  to_unsigned(to_nonnegative_int(value, max_value<int>()));
865  int num_digits = internal::count_digits(n);
866  if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
867  out = format_decimal<char_type>(out, n, num_digits);
868  }
869 
870  void write_nan() { std::copy_n("nan", 3, out); }
871  void write_pinf() { std::copy_n("inf", 3, out); }
872  void write_ninf() { std::copy_n("-inf", 4, out); }
873 
874  void format_localized(const tm& time, const char* format) {
875  if (isnan(val)) return write_nan();
876  auto locale = context.locale().template get<std::locale>();
877  auto& facet = std::use_facet<std::time_put<char_type>>(locale);
878  std::basic_ostringstream<char_type> os;
879  os.imbue(locale);
880  facet.put(os, os, ' ', &time, format, format + std::strlen(format));
881  auto str = os.str();
882  std::copy(str.begin(), str.end(), out);
883  }
884 
885  void on_text(const char_type* begin, const char_type* end) {
886  std::copy(begin, end, out);
887  }
888 
889  // These are not implemented because durations don't have date information.
890  void on_abbr_weekday() {}
891  void on_full_weekday() {}
894  void on_abbr_month() {}
895  void on_full_month() {}
899  void on_us_date() {}
900  void on_iso_date() {}
901  void on_utc_offset() {}
902  void on_tz_name() {}
903 
905  if (handle_nan_inf()) return;
906 
907  if (ns == numeric_system::standard) return write(hour(), 2);
908  auto time = tm();
909  time.tm_hour = to_nonnegative_int(hour(), 24);
910  format_localized(time, "%OH");
911  }
912 
914  if (handle_nan_inf()) return;
915 
916  if (ns == numeric_system::standard) return write(hour12(), 2);
917  auto time = tm();
918  time.tm_hour = to_nonnegative_int(hour12(), 12);
919  format_localized(time, "%OI");
920  }
921 
923  if (handle_nan_inf()) return;
924 
925  if (ns == numeric_system::standard) return write(minute(), 2);
926  auto time = tm();
927  time.tm_min = to_nonnegative_int(minute(), 60);
928  format_localized(time, "%OM");
929  }
930 
932  if (handle_nan_inf()) return;
933 
934  if (ns == numeric_system::standard) {
935  write(second(), 2);
936 #if FMT_SAFE_DURATION_CAST
937  // convert rep->Rep
938  using duration_rep = std::chrono::duration<rep, Period>;
939  using duration_Rep = std::chrono::duration<Rep, Period>;
940  auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{val});
941 #else
942  auto tmpval = std::chrono::duration<Rep, Period>(val);
943 #endif
944  auto ms = get_milliseconds(tmpval);
945  if (ms != std::chrono::milliseconds(0)) {
946  *out++ = '.';
947  write(ms.count(), 3);
948  }
949  return;
950  }
951  auto time = tm();
952  time.tm_sec = to_nonnegative_int(second(), 60);
953  format_localized(time, "%OS");
954  }
955 
957  if (handle_nan_inf()) return;
958 
959  format_localized(time(), "%r");
960  }
961 
963  if (handle_nan_inf()) {
964  *out++ = ':';
965  handle_nan_inf();
966  return;
967  }
968 
969  write(hour(), 2);
970  *out++ = ':';
971  write(minute(), 2);
972  }
973 
974  void on_iso_time() {
975  on_24_hour_time();
976  *out++ = ':';
977  if (handle_nan_inf()) return;
978  write(second(), 2);
979  }
980 
981  void on_am_pm() {
982  if (handle_nan_inf()) return;
983  format_localized(time(), "%p");
984  }
985 
987  if (handle_nan_inf()) return;
988  write_sign();
989  out = format_chrono_duration_value(out, val, precision);
990  }
991 
992  void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); }
993 };
994 } // namespace internal
995 
996 template <typename Rep, typename Period, typename Char>
997 struct formatter<std::chrono::duration<Rep, Period>, Char> {
998  private:
1005  using duration = std::chrono::duration<Rep, Period>;
1006 
1007  struct spec_handler {
1011 
1012  template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
1013  context.check_arg_id(arg_id);
1014  return arg_ref_type(arg_id);
1015  }
1016 
1018  context.check_arg_id(arg_id);
1019  return arg_ref_type(arg_id);
1020  }
1021 
1023  return arg_ref_type(context.next_arg_id());
1024  }
1025 
1026  void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
1027  void on_fill(Char fill) { f.specs.fill[0] = fill; }
1028  void on_align(align_t align) { f.specs.align = align; }
1029  void on_width(int width) { f.specs.width = width; }
1030  void on_precision(int _precision) { f.precision = _precision; }
1031  void end_precision() {}
1032 
1033  template <typename Id> void on_dynamic_width(Id arg_id) {
1034  f.width_ref = make_arg_ref(arg_id);
1035  }
1036 
1037  template <typename Id> void on_dynamic_precision(Id arg_id) {
1038  f.precision_ref = make_arg_ref(arg_id);
1039  }
1040  };
1041 
1043  struct parse_range {
1046  };
1047 
1049  auto begin = ctx.begin(), end = ctx.end();
1050  if (begin == end || *begin == '}') return {begin, begin};
1051  spec_handler handler{*this, ctx, format_str};
1052  begin = internal::parse_align(begin, end, handler);
1053  if (begin == end) return {begin, begin};
1054  begin = internal::parse_width(begin, end, handler);
1055  if (begin == end) return {begin, begin};
1056  if (*begin == '.') {
1057  if (std::is_floating_point<Rep>::value)
1058  begin = internal::parse_precision(begin, end, handler);
1059  else
1060  handler.on_error("precision not allowed for this argument type");
1061  }
1063  return {begin, end};
1064  }
1065 
1066  public:
1067  formatter() : precision(-1) {}
1068 
1070  -> decltype(ctx.begin()) {
1071  auto range = do_parse(ctx);
1072  format_str = basic_string_view<Char>(
1073  &*range.begin, internal::to_unsigned(range.end - range.begin));
1074  return range.end;
1075  }
1076 
1077  template <typename FormatContext>
1078  auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
1079  auto begin = format_str.begin(), end = format_str.end();
1080  // As a possible future optimization, we could avoid extra copying if width
1081  // is not specified.
1083  auto out = std::back_inserter(buf);
1084  using range = internal::output_range<decltype(ctx.out()), Char>;
1085  internal::basic_writer<range> w(range(ctx.out()));
1086  internal::handle_dynamic_spec<internal::width_checker>(specs.width,
1087  width_ref, ctx);
1088  internal::handle_dynamic_spec<internal::precision_checker>(
1089  precision, precision_ref, ctx);
1090  if (begin == end || *begin == '}') {
1091  out = internal::format_chrono_duration_value(out, d.count(), precision);
1092  internal::format_chrono_duration_unit<Period>(out);
1093  } else {
1095  ctx, out, d);
1096  f.precision = precision;
1097  parse_chrono_format(begin, end, f);
1098  }
1099  w.write(buf.data(), buf.size(), specs);
1100  return w.out();
1101  }
1102 };
1103 
1105 
1106 #endif // FMT_CHRONO_H_
basic_memory_buffer< Char > tm_format
Definition: chrono.h:439
#define FMT_BEGIN_NAMESPACE
Definition: core.h:163
#define FMT_ASSERT(condition, message)
Definition: core.h:233
std::basic_string< Char > format(const text_style &ts, const S &format_str, const Args &... args)
Definition: color.h:562
std::size_t size() const FMT_NOEXCEPT
Definition: core.h:607
FMT_NORETURN void on_abbr_month()
Definition: chrono.h:642
void on_loc_date(numeric_system)
Definition: chrono.h:897
type
Definition: format.h:1005
FMT_CONSTEXPR iterator end() const
Definition: core.h:326
std::chrono::duration< rep, std::milli > milliseconds
Definition: chrono.h:789
null localtime_s(...)
Definition: chrono.h:311
Definition: format.h:1004
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT
Definition: core.h:501
FMT_NORETURN void on_loc_time(numeric_system)
Definition: chrono.h:650
FMT_CONSTEXPR const Char * parse_chrono_format(const Char *begin, const Char *end, Handler &&handler)
Definition: chrono.h:478
void on_12_hour(numeric_system)
Definition: chrono.h:645
void on_minute(numeric_system ns)
Definition: chrono.h:922
bool_constant< is_integral< T >::value &&!std::is_same< T, bool >::value &&!std::is_same< T, char >::value &&!std::is_same< T, wchar_t >::value > is_integer
Definition: format.h:1974
OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision)
Definition: chrono.h:763
T mod(T x, int y)
Definition: chrono.h:698
FMT_NORETURN void on_full_weekday()
Definition: chrono.h:639
FMT_NORETURN void on_dec0_weekday(numeric_system)
Definition: chrono.h:640
typename std::make_unsigned< T >::type type
Definition: chrono.h:714
FMT_NORETURN void on_utc_offset()
Definition: chrono.h:659
To safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from, int &ec)
Definition: chrono.h:170
FMT_CONSTEXPR void check_arg_id(int)
Definition: core.h:522
FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view< Char > arg_id)
Definition: chrono.h:1017
void write(Rep value, int width)
Definition: chrono.h:860
T * data() FMT_NOEXCEPT
Definition: core.h:613
bool isfinite(T)
Definition: chrono.h:673
void on_datetime(numeric_system)
Definition: chrono.h:896
void format_localized(const tm &time, const char *format)
Definition: chrono.h:874
#define FMT_THROW(x)
Definition: format.h:94
T * begin() FMT_NOEXCEPT
Definition: core.h:603
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id)
Definition: chrono.h:1022
void on_second(numeric_system ns)
Definition: chrono.h:931
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
Definition: chrono.h:403
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out())
Definition: chrono.h:415
FMT_CONSTEXPR bool is_negative(T value)
Definition: format.h:708
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT
Definition: core.h:494
conditional_t< std::is_integral< Rep >::value &&sizeof(Rep)< sizeof(int), unsigned, typename make_unsigned_or_unchanged< Rep >::type > rep
Definition: chrono.h:785
FMT_CONSTEXPR int next_arg_id()
Definition: core.h:512
FMT_CONSTEXPR const Char * parse_width(const Char *begin, const Char *end, Handler &&handler)
Definition: format.h:2380
std::tm localtime(std::time_t time)
Definition: chrono.h:317
int count_digits(uint64_t n)
Definition: format.h:755
OutputIt format_to(OutputIt out, const CompiledFormat &cf, const Args &... args)
Definition: compile.h:559
#define FMT_END_NAMESPACE
Definition: core.h:158
#define FMT_NORETURN
Definition: core.h:124
void on_text(const char_type *begin, const char_type *end)
Definition: chrono.h:885
FMT_CONSTEXPR const char * get_units()
Definition: chrono.h:443
typename basic_format_parse_context< Char >::iterator iterator
Definition: chrono.h:1042
void on_24_hour(numeric_system ns)
Definition: chrono.h:904
FMT_NORETURN void on_full_month()
Definition: chrono.h:643
FMT_NORETURN void on_loc_date(numeric_system)
Definition: chrono.h:649
FMT_NORETURN void on_dec1_weekday(numeric_system)
Definition: chrono.h:641
std::chrono::duration< Rep, Period > duration
Definition: chrono.h:1005
OutputIterator copy(const RangeT &range, OutputIterator out)
Definition: ranges.h:58
std::chrono::duration< Rep, std::milli > get_milliseconds(std::chrono::duration< Rep, Period > d)
Definition: chrono.h:730
void on_second(numeric_system)
Definition: chrono.h:647
#define FMT_ENABLE_IF(...)
Definition: core.h:220
typename std::conditional< B, T, F >::type conditional_t
Definition: core.h:206
void reserve(std::size_t new_capacity)
Definition: core.h:630
FMT_CONSTEXPR const Char * parse_precision(const Char *begin, const Char *end, Handler &&handler)
Definition: format.h:2397
int to_nonnegative_int(T value, int upper)
Definition: chrono.h:683
auto format(const duration &d, FormatContext &ctx) -> decltype(ctx.out())
Definition: chrono.h:1078
std::tm gmtime(std::time_t time)
Definition: chrono.h:354
FMT_NORETURN void on_us_date()
Definition: chrono.h:651
FMT_NORETURN void report_no_date()
Definition: chrono.h:635
FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context< Char > &ctx)
Definition: chrono.h:1048
type
Definition: core.h:687
typename FormatContext::char_type char_type
Definition: chrono.h:792
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int &ec)
Definition: chrono.h:39
std::chrono::duration< rep > seconds
Definition: chrono.h:787
std::size_t capacity() const FMT_NOEXCEPT
Definition: core.h:610
void on_dec0_weekday(numeric_system)
Definition: chrono.h:892
void resize(std::size_t new_size)
Definition: core.h:621
FMT_NORETURN void on_abbr_weekday()
Definition: chrono.h:638
To fmt_safe_duration_cast(std::chrono::duration< FromRep, FromPeriod > from)
Definition: chrono.h:720
chrono_formatter(FormatContext &ctx, OutputIt o, std::chrono::duration< Rep, Period > d)
Definition: chrono.h:794
null gmtime_r(...)
Definition: chrono.h:312
T * end() FMT_NOEXCEPT
Definition: core.h:604
std::tm time() const
Definition: chrono.h:845
FMT_CONSTEXPR iterator begin() const
Definition: core.h:325
std::size_t strftime(wchar_t *str, std::size_t count, const wchar_t *format, const std::tm *time)
Definition: chrono.h:395
void on_text(const Char *, const Char *)
Definition: chrono.h:637
#define FMT_NOMACRO
Definition: chrono.h:307
void on_minute(numeric_system)
Definition: chrono.h:646
void on_12_hour(numeric_system ns)
Definition: chrono.h:913
FMT_CONSTEXPR To safe_float_conversion(const From from, int &ec)
Definition: chrono.h:136
bool isnan(T)
Definition: chrono.h:664
FMT_NORETURN void on_iso_date()
Definition: chrono.h:652
FormatContext & context
Definition: chrono.h:779
null gmtime_s(...)
Definition: chrono.h:313
FMT_CONSTEXPR const Char * parse_align(const Char *begin, const Char *end, Handler &&handler)
Definition: format.h:2340
std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time)
Definition: chrono.h:390
conditional_t< std::numeric_limits< T >::digits<=32, uint32_t, conditional_t< std::numeric_limits< T >::digits<=64, uint64_t, uint128_t > > uint32_or_64_or_128_t
Definition: format.h:721
#define FMT_CONSTEXPR
Definition: core.h:75
void write(std::basic_ostream< Char > &os, buffer< Char > &buf)
Definition: ostream.h:78
static OutputIt format_chrono_duration_unit(OutputIt out)
Definition: chrono.h:770
FMT_NORETURN void on_tz_name()
Definition: chrono.h:660
FMT_CONSTEXPR auto parse(basic_format_parse_context< Char > &ctx) -> decltype(ctx.begin())
Definition: chrono.h:1069
FMT_CONSTEXPR std::make_unsigned< Int >::type to_unsigned(Int value)
Definition: core.h:265
void on_loc_time(numeric_system)
Definition: chrono.h:898
numeric_system
Definition: chrono.h:470
FMT_NORETURN void on_datetime(numeric_system)
Definition: chrono.h:648
const void * ptr(const T *p)
Definition: format.h:3159
void on_dec1_weekday(numeric_system)
Definition: chrono.h:893
void on_24_hour(numeric_system)
Definition: chrono.h:644