诸暨麻将添加redis
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

830 lignes
25 KiB

  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 "format.h"
  10. #include "locale.h"
  11. #include <chrono>
  12. #include <ctime>
  13. #include <locale>
  14. #include <sstream>
  15. // enable safe chrono durations, unless explicitly disabled
  16. #ifndef FMT_SAFE_DURATION_CAST
  17. # define FMT_SAFE_DURATION_CAST 1
  18. #endif
  19. #if FMT_SAFE_DURATION_CAST
  20. # include "safe-duration-cast.h"
  21. #endif
  22. FMT_BEGIN_NAMESPACE
  23. // Prevents expansion of a preceding token as a function-style macro.
  24. // Usage: f FMT_NOMACRO()
  25. #define FMT_NOMACRO
  26. namespace internal {
  27. inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
  28. inline null<> localtime_s(...) { return null<>(); }
  29. inline null<> gmtime_r(...) { return null<>(); }
  30. inline null<> gmtime_s(...) { return null<>(); }
  31. } // namespace internal
  32. // Thread-safe replacement for std::localtime
  33. inline std::tm localtime(std::time_t time) {
  34. struct dispatcher {
  35. std::time_t time_;
  36. std::tm tm_;
  37. dispatcher(std::time_t t) : time_(t) {}
  38. bool run() {
  39. using namespace fmt::internal;
  40. return handle(localtime_r(&time_, &tm_));
  41. }
  42. bool handle(std::tm* tm) { return tm != nullptr; }
  43. bool handle(internal::null<>) {
  44. using namespace fmt::internal;
  45. return fallback(localtime_s(&tm_, &time_));
  46. }
  47. bool fallback(int res) { return res == 0; }
  48. #if !FMT_MSC_VER
  49. bool fallback(internal::null<>) {
  50. using namespace fmt::internal;
  51. std::tm* tm = std::localtime(&time_);
  52. if (tm) tm_ = *tm;
  53. return tm != nullptr;
  54. }
  55. #endif
  56. };
  57. dispatcher lt(time);
  58. // Too big time values may be unsupported.
  59. if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
  60. return lt.tm_;
  61. }
  62. // Thread-safe replacement for std::gmtime
  63. inline std::tm gmtime(std::time_t time) {
  64. struct dispatcher {
  65. std::time_t time_;
  66. std::tm tm_;
  67. dispatcher(std::time_t t) : time_(t) {}
  68. bool run() {
  69. using namespace fmt::internal;
  70. return handle(gmtime_r(&time_, &tm_));
  71. }
  72. bool handle(std::tm* tm) { return tm != nullptr; }
  73. bool handle(internal::null<>) {
  74. using namespace fmt::internal;
  75. return fallback(gmtime_s(&tm_, &time_));
  76. }
  77. bool fallback(int res) { return res == 0; }
  78. #if !FMT_MSC_VER
  79. bool fallback(internal::null<>) {
  80. std::tm* tm = std::gmtime(&time_);
  81. if (tm) tm_ = *tm;
  82. return tm != nullptr;
  83. }
  84. #endif
  85. };
  86. dispatcher gt(time);
  87. // Too big time values may be unsupported.
  88. if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
  89. return gt.tm_;
  90. }
  91. namespace internal {
  92. inline std::size_t strftime(char* str, std::size_t count, const char* format,
  93. const std::tm* time) {
  94. return std::strftime(str, count, format, time);
  95. }
  96. inline std::size_t strftime(wchar_t* str, std::size_t count,
  97. const wchar_t* format, const std::tm* time) {
  98. return std::wcsftime(str, count, format, time);
  99. }
  100. } // namespace internal
  101. template <typename Char> struct formatter<std::tm, Char> {
  102. template <typename ParseContext>
  103. auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  104. auto it = ctx.begin();
  105. if (it != ctx.end() && *it == ':') ++it;
  106. auto end = it;
  107. while (end != ctx.end() && *end != '}') ++end;
  108. tm_format.reserve(internal::to_unsigned(end - it + 1));
  109. tm_format.append(it, end);
  110. tm_format.push_back('\0');
  111. return end;
  112. }
  113. template <typename FormatContext>
  114. auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
  115. basic_memory_buffer<Char> buf;
  116. std::size_t start = buf.size();
  117. for (;;) {
  118. std::size_t size = buf.capacity() - start;
  119. std::size_t count =
  120. internal::strftime(&buf[start], size, &tm_format[0], &tm);
  121. if (count != 0) {
  122. buf.resize(start + count);
  123. break;
  124. }
  125. if (size >= tm_format.size() * 256) {
  126. // If the buffer is 256 times larger than the format string, assume
  127. // that `strftime` gives an empty result. There doesn't seem to be a
  128. // better way to distinguish the two cases:
  129. // https://github.com/fmtlib/fmt/issues/367
  130. break;
  131. }
  132. const std::size_t MIN_GROWTH = 10;
  133. buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
  134. }
  135. return std::copy(buf.begin(), buf.end(), ctx.out());
  136. }
  137. basic_memory_buffer<Char> tm_format;
  138. };
  139. namespace internal {
  140. template <typename Period> FMT_CONSTEXPR const char* get_units() {
  141. return nullptr;
  142. }
  143. template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
  144. template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
  145. template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
  146. template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
  147. template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
  148. template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
  149. template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
  150. template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
  151. template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
  152. template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
  153. template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
  154. template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
  155. template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
  156. template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
  157. template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
  158. template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
  159. template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
  160. template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
  161. return "m";
  162. }
  163. template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
  164. return "h";
  165. }
  166. enum class numeric_system {
  167. standard,
  168. // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
  169. alternative
  170. };
  171. // Parses a put_time-like format string and invokes handler actions.
  172. template <typename Char, typename Handler>
  173. FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
  174. const Char* end,
  175. Handler&& handler) {
  176. auto ptr = begin;
  177. while (ptr != end) {
  178. auto c = *ptr;
  179. if (c == '}') break;
  180. if (c != '%') {
  181. ++ptr;
  182. continue;
  183. }
  184. if (begin != ptr) handler.on_text(begin, ptr);
  185. ++ptr; // consume '%'
  186. if (ptr == end) FMT_THROW(format_error("invalid format"));
  187. c = *ptr++;
  188. switch (c) {
  189. case '%':
  190. handler.on_text(ptr - 1, ptr);
  191. break;
  192. case 'n': {
  193. const char newline[] = "\n";
  194. handler.on_text(newline, newline + 1);
  195. break;
  196. }
  197. case 't': {
  198. const char tab[] = "\t";
  199. handler.on_text(tab, tab + 1);
  200. break;
  201. }
  202. // Day of the week:
  203. case 'a':
  204. handler.on_abbr_weekday();
  205. break;
  206. case 'A':
  207. handler.on_full_weekday();
  208. break;
  209. case 'w':
  210. handler.on_dec0_weekday(numeric_system::standard);
  211. break;
  212. case 'u':
  213. handler.on_dec1_weekday(numeric_system::standard);
  214. break;
  215. // Month:
  216. case 'b':
  217. handler.on_abbr_month();
  218. break;
  219. case 'B':
  220. handler.on_full_month();
  221. break;
  222. // Hour, minute, second:
  223. case 'H':
  224. handler.on_24_hour(numeric_system::standard);
  225. break;
  226. case 'I':
  227. handler.on_12_hour(numeric_system::standard);
  228. break;
  229. case 'M':
  230. handler.on_minute(numeric_system::standard);
  231. break;
  232. case 'S':
  233. handler.on_second(numeric_system::standard);
  234. break;
  235. // Other:
  236. case 'c':
  237. handler.on_datetime(numeric_system::standard);
  238. break;
  239. case 'x':
  240. handler.on_loc_date(numeric_system::standard);
  241. break;
  242. case 'X':
  243. handler.on_loc_time(numeric_system::standard);
  244. break;
  245. case 'D':
  246. handler.on_us_date();
  247. break;
  248. case 'F':
  249. handler.on_iso_date();
  250. break;
  251. case 'r':
  252. handler.on_12_hour_time();
  253. break;
  254. case 'R':
  255. handler.on_24_hour_time();
  256. break;
  257. case 'T':
  258. handler.on_iso_time();
  259. break;
  260. case 'p':
  261. handler.on_am_pm();
  262. break;
  263. case 'Q':
  264. handler.on_duration_value();
  265. break;
  266. case 'q':
  267. handler.on_duration_unit();
  268. break;
  269. case 'z':
  270. handler.on_utc_offset();
  271. break;
  272. case 'Z':
  273. handler.on_tz_name();
  274. break;
  275. // Alternative representation:
  276. case 'E': {
  277. if (ptr == end) FMT_THROW(format_error("invalid format"));
  278. c = *ptr++;
  279. switch (c) {
  280. case 'c':
  281. handler.on_datetime(numeric_system::alternative);
  282. break;
  283. case 'x':
  284. handler.on_loc_date(numeric_system::alternative);
  285. break;
  286. case 'X':
  287. handler.on_loc_time(numeric_system::alternative);
  288. break;
  289. default:
  290. FMT_THROW(format_error("invalid format"));
  291. }
  292. break;
  293. }
  294. case 'O':
  295. if (ptr == end) FMT_THROW(format_error("invalid format"));
  296. c = *ptr++;
  297. switch (c) {
  298. case 'w':
  299. handler.on_dec0_weekday(numeric_system::alternative);
  300. break;
  301. case 'u':
  302. handler.on_dec1_weekday(numeric_system::alternative);
  303. break;
  304. case 'H':
  305. handler.on_24_hour(numeric_system::alternative);
  306. break;
  307. case 'I':
  308. handler.on_12_hour(numeric_system::alternative);
  309. break;
  310. case 'M':
  311. handler.on_minute(numeric_system::alternative);
  312. break;
  313. case 'S':
  314. handler.on_second(numeric_system::alternative);
  315. break;
  316. default:
  317. FMT_THROW(format_error("invalid format"));
  318. }
  319. break;
  320. default:
  321. FMT_THROW(format_error("invalid format"));
  322. }
  323. begin = ptr;
  324. }
  325. if (begin != ptr) handler.on_text(begin, ptr);
  326. return ptr;
  327. }
  328. struct chrono_format_checker {
  329. FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
  330. template <typename Char> void on_text(const Char*, const Char*) {}
  331. FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
  332. FMT_NORETURN void on_full_weekday() { report_no_date(); }
  333. FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
  334. FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
  335. FMT_NORETURN void on_abbr_month() { report_no_date(); }
  336. FMT_NORETURN void on_full_month() { report_no_date(); }
  337. void on_24_hour(numeric_system) {}
  338. void on_12_hour(numeric_system) {}
  339. void on_minute(numeric_system) {}
  340. void on_second(numeric_system) {}
  341. FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
  342. FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
  343. FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
  344. FMT_NORETURN void on_us_date() { report_no_date(); }
  345. FMT_NORETURN void on_iso_date() { report_no_date(); }
  346. void on_12_hour_time() {}
  347. void on_24_hour_time() {}
  348. void on_iso_time() {}
  349. void on_am_pm() {}
  350. void on_duration_value() {}
  351. void on_duration_unit() {}
  352. FMT_NORETURN void on_utc_offset() { report_no_date(); }
  353. FMT_NORETURN void on_tz_name() { report_no_date(); }
  354. };
  355. template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  356. inline bool isnan(T) {
  357. return false;
  358. }
  359. template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  360. inline bool isnan(T value) {
  361. return std::isnan(value);
  362. }
  363. template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  364. inline bool isfinite(T) {
  365. return true;
  366. }
  367. template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  368. inline bool isfinite(T value) {
  369. return std::isfinite(value);
  370. }
  371. // Convers value to int and checks that it's in the range [0, upper).
  372. template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  373. inline int to_nonnegative_int(T value, int upper) {
  374. FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
  375. (void)upper;
  376. return static_cast<int>(value);
  377. }
  378. template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
  379. inline int to_nonnegative_int(T value, int upper) {
  380. FMT_ASSERT(
  381. std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
  382. "invalid value");
  383. (void)upper;
  384. return static_cast<int>(value);
  385. }
  386. template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
  387. inline T mod(T x, int y) {
  388. return x % y;
  389. }
  390. template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
  391. inline T mod(T x, int y) {
  392. return std::fmod(x, static_cast<T>(y));
  393. }
  394. // If T is an integral type, maps T to its unsigned counterpart, otherwise
  395. // leaves it unchanged (unlike std::make_unsigned).
  396. template <typename T, bool INTEGRAL = std::is_integral<T>::value>
  397. struct make_unsigned_or_unchanged {
  398. using type = T;
  399. };
  400. template <typename T> struct make_unsigned_or_unchanged<T, true> {
  401. using type = typename std::make_unsigned<T>::type;
  402. };
  403. #if FMT_SAFE_DURATION_CAST
  404. // throwing version of safe_duration_cast
  405. template <typename To, typename FromRep, typename FromPeriod>
  406. To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) {
  407. int ec;
  408. To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
  409. if (ec) FMT_THROW(format_error("cannot format duration"));
  410. return to;
  411. }
  412. #endif
  413. template <typename Rep, typename Period,
  414. FMT_ENABLE_IF(std::is_integral<Rep>::value)>
  415. inline std::chrono::duration<Rep, std::milli> get_milliseconds(
  416. std::chrono::duration<Rep, Period> d) {
  417. // this may overflow and/or the result may not fit in the
  418. // target type.
  419. #if FMT_SAFE_DURATION_CAST
  420. using CommonSecondsType =
  421. typename std::common_type<decltype(d), std::chrono::seconds>::type;
  422. const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
  423. const auto d_as_whole_seconds =
  424. fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
  425. // this conversion should be nonproblematic
  426. const auto diff = d_as_common - d_as_whole_seconds;
  427. const auto ms =
  428. fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
  429. return ms;
  430. #else
  431. auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
  432. return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
  433. #endif
  434. }
  435. template <typename Rep, typename Period,
  436. FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
  437. inline std::chrono::duration<Rep, std::milli> get_milliseconds(
  438. std::chrono::duration<Rep, Period> d) {
  439. using common_type = typename std::common_type<Rep, std::intmax_t>::type;
  440. auto ms = mod(d.count() * static_cast<common_type>(Period::num) /
  441. static_cast<common_type>(Period::den) * 1000,
  442. 1000);
  443. return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
  444. }
  445. template <typename Rep, typename OutputIt>
  446. OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
  447. if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
  448. return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
  449. val);
  450. }
  451. template <typename Period, typename OutputIt>
  452. static OutputIt format_chrono_duration_unit(OutputIt out) {
  453. if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
  454. if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
  455. return format_to(out, "[{}/{}]s", Period::num, Period::den);
  456. }
  457. template <typename FormatContext, typename OutputIt, typename Rep,
  458. typename Period>
  459. struct chrono_formatter {
  460. FormatContext& context;
  461. OutputIt out;
  462. int precision;
  463. // rep is unsigned to avoid overflow.
  464. using rep =
  465. conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
  466. unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
  467. rep val;
  468. using seconds = std::chrono::duration<rep>;
  469. seconds s;
  470. using milliseconds = std::chrono::duration<rep, std::milli>;
  471. bool negative;
  472. using char_type = typename FormatContext::char_type;
  473. explicit chrono_formatter(FormatContext& ctx, OutputIt o,
  474. std::chrono::duration<Rep, Period> d)
  475. : context(ctx), out(o), val(d.count()), negative(false) {
  476. if (d.count() < 0) {
  477. val = 0 - val;
  478. negative = true;
  479. }
  480. // this may overflow and/or the result may not fit in the
  481. // target type.
  482. #if FMT_SAFE_DURATION_CAST
  483. // might need checked conversion (rep!=Rep)
  484. auto tmpval = std::chrono::duration<rep, Period>(val);
  485. s = fmt_safe_duration_cast<seconds>(tmpval);
  486. #else
  487. s = std::chrono::duration_cast<seconds>(
  488. std::chrono::duration<rep, Period>(val));
  489. #endif
  490. }
  491. // returns true if nan or inf, writes to out.
  492. bool handle_nan_inf() {
  493. if (isfinite(val)) {
  494. return false;
  495. }
  496. if (isnan(val)) {
  497. write_nan();
  498. return true;
  499. }
  500. // must be +-inf
  501. if (val > 0) {
  502. write_pinf();
  503. } else {
  504. write_ninf();
  505. }
  506. return true;
  507. }
  508. Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); }
  509. Rep hour12() const {
  510. Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
  511. return hour <= 0 ? 12 : hour;
  512. }
  513. Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); }
  514. Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); }
  515. std::tm time() const {
  516. auto time = std::tm();
  517. time.tm_hour = to_nonnegative_int(hour(), 24);
  518. time.tm_min = to_nonnegative_int(minute(), 60);
  519. time.tm_sec = to_nonnegative_int(second(), 60);
  520. return time;
  521. }
  522. void write_sign() {
  523. if (negative) {
  524. *out++ = '-';
  525. negative = false;
  526. }
  527. }
  528. void write(Rep value, int width) {
  529. write_sign();
  530. if (isnan(value)) return write_nan();
  531. uint32_or_64_t<int> n = to_unsigned(
  532. to_nonnegative_int(value, (std::numeric_limits<int>::max)()));
  533. int num_digits = internal::count_digits(n);
  534. if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
  535. out = format_decimal<char_type>(out, n, num_digits);
  536. }
  537. void write_nan() { std::copy_n("nan", 3, out); }
  538. void write_pinf() { std::copy_n("inf", 3, out); }
  539. void write_ninf() { std::copy_n("-inf", 4, out); }
  540. void format_localized(const tm& time, const char* format) {
  541. if (isnan(val)) return write_nan();
  542. auto locale = context.locale().template get<std::locale>();
  543. auto& facet = std::use_facet<std::time_put<char_type>>(locale);
  544. std::basic_ostringstream<char_type> os;
  545. os.imbue(locale);
  546. facet.put(os, os, ' ', &time, format, format + std::strlen(format));
  547. auto str = os.str();
  548. std::copy(str.begin(), str.end(), out);
  549. }
  550. void on_text(const char_type* begin, const char_type* end) {
  551. std::copy(begin, end, out);
  552. }
  553. // These are not implemented because durations don't have date information.
  554. void on_abbr_weekday() {}
  555. void on_full_weekday() {}
  556. void on_dec0_weekday(numeric_system) {}
  557. void on_dec1_weekday(numeric_system) {}
  558. void on_abbr_month() {}
  559. void on_full_month() {}
  560. void on_datetime(numeric_system) {}
  561. void on_loc_date(numeric_system) {}
  562. void on_loc_time(numeric_system) {}
  563. void on_us_date() {}
  564. void on_iso_date() {}
  565. void on_utc_offset() {}
  566. void on_tz_name() {}
  567. void on_24_hour(numeric_system ns) {
  568. if (handle_nan_inf()) return;
  569. if (ns == numeric_system::standard) return write(hour(), 2);
  570. auto time = tm();
  571. time.tm_hour = to_nonnegative_int(hour(), 24);
  572. format_localized(time, "%OH");
  573. }
  574. void on_12_hour(numeric_system ns) {
  575. if (handle_nan_inf()) return;
  576. if (ns == numeric_system::standard) return write(hour12(), 2);
  577. auto time = tm();
  578. time.tm_hour = to_nonnegative_int(hour12(), 12);
  579. format_localized(time, "%OI");
  580. }
  581. void on_minute(numeric_system ns) {
  582. if (handle_nan_inf()) return;
  583. if (ns == numeric_system::standard) return write(minute(), 2);
  584. auto time = tm();
  585. time.tm_min = to_nonnegative_int(minute(), 60);
  586. format_localized(time, "%OM");
  587. }
  588. void on_second(numeric_system ns) {
  589. if (handle_nan_inf()) return;
  590. if (ns == numeric_system::standard) {
  591. write(second(), 2);
  592. #if FMT_SAFE_DURATION_CAST
  593. // convert rep->Rep
  594. using duration_rep = std::chrono::duration<rep, Period>;
  595. using duration_Rep = std::chrono::duration<Rep, Period>;
  596. auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{val});
  597. #else
  598. auto tmpval = std::chrono::duration<Rep, Period>(val);
  599. #endif
  600. auto ms = get_milliseconds(tmpval);
  601. if (ms != std::chrono::milliseconds(0)) {
  602. *out++ = '.';
  603. write(ms.count(), 3);
  604. }
  605. return;
  606. }
  607. auto time = tm();
  608. time.tm_sec = to_nonnegative_int(second(), 60);
  609. format_localized(time, "%OS");
  610. }
  611. void on_12_hour_time() {
  612. if (handle_nan_inf()) return;
  613. format_localized(time(), "%r");
  614. }
  615. void on_24_hour_time() {
  616. if (handle_nan_inf()) {
  617. *out++ = ':';
  618. handle_nan_inf();
  619. return;
  620. }
  621. write(hour(), 2);
  622. *out++ = ':';
  623. write(minute(), 2);
  624. }
  625. void on_iso_time() {
  626. on_24_hour_time();
  627. *out++ = ':';
  628. if (handle_nan_inf()) return;
  629. write(second(), 2);
  630. }
  631. void on_am_pm() {
  632. if (handle_nan_inf()) return;
  633. format_localized(time(), "%p");
  634. }
  635. void on_duration_value() {
  636. if (handle_nan_inf()) return;
  637. write_sign();
  638. out = format_chrono_duration_value(out, val, precision);
  639. }
  640. void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); }
  641. };
  642. } // namespace internal
  643. template <typename Rep, typename Period, typename Char>
  644. struct formatter<std::chrono::duration<Rep, Period>, Char> {
  645. private:
  646. basic_format_specs<Char> specs;
  647. int precision;
  648. using arg_ref_type = internal::arg_ref<Char>;
  649. arg_ref_type width_ref;
  650. arg_ref_type precision_ref;
  651. mutable basic_string_view<Char> format_str;
  652. using duration = std::chrono::duration<Rep, Period>;
  653. struct spec_handler {
  654. formatter& f;
  655. basic_parse_context<Char>& context;
  656. basic_string_view<Char> format_str;
  657. template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
  658. context.check_arg_id(arg_id);
  659. return arg_ref_type(arg_id);
  660. }
  661. FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
  662. context.check_arg_id(arg_id);
  663. const auto str_val = internal::string_view_metadata(format_str, arg_id);
  664. return arg_ref_type(str_val);
  665. }
  666. FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
  667. return arg_ref_type(context.next_arg_id());
  668. }
  669. void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
  670. void on_fill(Char fill) { f.specs.fill[0] = fill; }
  671. void on_align(align_t align) { f.specs.align = align; }
  672. void on_width(unsigned width) { f.specs.width = width; }
  673. void on_precision(unsigned precision) { f.precision = precision; }
  674. void end_precision() {}
  675. template <typename Id> void on_dynamic_width(Id arg_id) {
  676. f.width_ref = make_arg_ref(arg_id);
  677. }
  678. template <typename Id> void on_dynamic_precision(Id arg_id) {
  679. f.precision_ref = make_arg_ref(arg_id);
  680. }
  681. };
  682. using iterator = typename basic_parse_context<Char>::iterator;
  683. struct parse_range {
  684. iterator begin;
  685. iterator end;
  686. };
  687. FMT_CONSTEXPR parse_range do_parse(basic_parse_context<Char>& ctx) {
  688. auto begin = ctx.begin(), end = ctx.end();
  689. if (begin == end || *begin == '}') return {begin, begin};
  690. spec_handler handler{*this, ctx, format_str};
  691. begin = internal::parse_align(begin, end, handler);
  692. if (begin == end) return {begin, begin};
  693. begin = internal::parse_width(begin, end, handler);
  694. if (begin == end) return {begin, begin};
  695. if (*begin == '.') {
  696. if (std::is_floating_point<Rep>::value)
  697. begin = internal::parse_precision(begin, end, handler);
  698. else
  699. handler.on_error("precision not allowed for this argument type");
  700. }
  701. end = parse_chrono_format(begin, end, internal::chrono_format_checker());
  702. return {begin, end};
  703. }
  704. public:
  705. formatter() : precision(-1) {}
  706. FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
  707. -> decltype(ctx.begin()) {
  708. auto range = do_parse(ctx);
  709. format_str = basic_string_view<Char>(
  710. &*range.begin, internal::to_unsigned(range.end - range.begin));
  711. return range.end;
  712. }
  713. template <typename FormatContext>
  714. auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
  715. auto begin = format_str.begin(), end = format_str.end();
  716. // As a possible future optimization, we could avoid extra copying if width
  717. // is not specified.
  718. basic_memory_buffer<Char> buf;
  719. auto out = std::back_inserter(buf);
  720. using range = internal::output_range<decltype(ctx.out()), Char>;
  721. internal::basic_writer<range> w(range(ctx.out()));
  722. internal::handle_dynamic_spec<internal::width_checker>(
  723. specs.width, width_ref, ctx, format_str.begin());
  724. internal::handle_dynamic_spec<internal::precision_checker>(
  725. precision, precision_ref, ctx, format_str.begin());
  726. if (begin == end || *begin == '}') {
  727. out = internal::format_chrono_duration_value(out, d.count(), precision);
  728. internal::format_chrono_duration_unit<Period>(out);
  729. } else {
  730. internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
  731. ctx, out, d);
  732. f.precision = precision;
  733. parse_chrono_format(begin, end, f);
  734. }
  735. w.write(buf.data(), buf.size(), specs);
  736. return w.out();
  737. }
  738. };
  739. FMT_END_NAMESPACE
  740. #endif // FMT_CHRONO_H_