You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1118 lines
35 KiB

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