duration_get.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. // (C) Copyright Howard Hinnant
  2. // (C) Copyright 2011 Vicente J. Botet Escriba
  3. // Use, modification and distribution are subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt).
  6. //
  7. #ifndef BOOST_CHRONO_IO_DURATION_GET_HPP
  8. #define BOOST_CHRONO_IO_DURATION_GET_HPP
  9. #include <boost/chrono/config.hpp>
  10. #include <string>
  11. #include <boost/type_traits/is_scalar.hpp>
  12. #include <boost/utility/enable_if.hpp>
  13. #include <boost/type_traits/is_signed.hpp>
  14. #include <boost/mpl/if.hpp>
  15. #include <boost/integer/common_factor_rt.hpp>
  16. #include <boost/chrono/detail/scan_keyword.hpp>
  17. #include <boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp>
  18. #include <boost/chrono/process_cpu_clocks.hpp>
  19. #include <boost/assert.hpp>
  20. #include <locale>
  21. /**
  22. * Duration formatting facet for input.
  23. */
  24. namespace boost
  25. {
  26. namespace chrono
  27. {
  28. namespace detail
  29. {
  30. template <class Rep, bool = is_scalar<Rep>::value>
  31. struct duration_io_intermediate
  32. {
  33. typedef Rep type;
  34. };
  35. template <class Rep>
  36. struct duration_io_intermediate<Rep, true>
  37. {
  38. typedef typename mpl::if_c<is_floating_point<Rep>::value, long double, typename mpl::if_c<
  39. is_signed<Rep>::value, long long, unsigned long long>::type>::type type;
  40. };
  41. template <class Rep>
  42. struct duration_io_intermediate<process_times<Rep>, false>
  43. {
  44. typedef process_times<typename duration_io_intermediate<Rep>::type> type;
  45. };
  46. template <typename intermediate_type>
  47. typename enable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type& r,
  48. unsigned long long& den, std::ios_base::iostate& err)
  49. {
  50. typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
  51. // Reduce r * num / den
  52. common_type_t t = integer::gcd<common_type_t>(common_type_t(r), common_type_t(den));
  53. r /= t;
  54. den /= t;
  55. if (den != 1)
  56. {
  57. // Conversion to Period is integral and not exact
  58. err |= std::ios_base::failbit;
  59. return false;
  60. }
  61. return true;
  62. }
  63. template <typename intermediate_type>
  64. typename disable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type&, unsigned long long&,
  65. std::ios_base::iostate&)
  66. {
  67. return true;
  68. }
  69. }
  70. /**
  71. * @c duration_get is used to parse a character sequence, extracting
  72. * components of a duration into a class duration.
  73. * Each get member parses a format as produced by a corresponding format specifier to time_put<>::put.
  74. * If the sequence being parsed matches the correct format, the
  75. * corresponding member of the class duration argument are set to the
  76. * value used to produce the sequence;
  77. * otherwise either an error is reported or unspecified values are assigned.
  78. * In other words, user confirmation is required for reliable parsing of
  79. * user-entered durations, but machine-generated formats can be parsed
  80. * reliably. This allows parsers to be aggressive about interpreting user
  81. * variations on standard formats.
  82. *
  83. * If the end iterator is reached during parsing of the get() member
  84. * function, the member sets std::ios_base::eofbit in err.
  85. */
  86. template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> >
  87. class duration_get: public std::locale::facet
  88. {
  89. public:
  90. /**
  91. * Type of character the facet is instantiated on.
  92. */
  93. typedef CharT char_type;
  94. /**
  95. * Type of character string passed to member functions.
  96. */
  97. typedef std::basic_string<CharT> string_type;
  98. /**
  99. * Type of iterator used to scan the character buffer.
  100. */
  101. typedef InputIterator iter_type;
  102. /**
  103. * Construct a @c duration_get facet.
  104. * @param refs
  105. * @Effects Construct a @c duration_get facet.
  106. * If the @c refs argument is @c 0 then destruction of the object is
  107. * delegated to the @c locale, or locales, containing it. This allows
  108. * the user to ignore lifetime management issues. On the other had,
  109. * if @c refs is @c 1 then the object must be explicitly deleted;
  110. * the @c locale will not do so. In this case, the object can be
  111. * maintained across the lifetime of multiple locales.
  112. */
  113. explicit duration_get(size_t refs = 0) :
  114. std::locale::facet(refs)
  115. {
  116. }
  117. /**
  118. * @param s start input stream iterator
  119. * @param end end input stream iterator
  120. * @param ios a reference to a ios_base
  121. * @param err the ios_base state
  122. * @param d the duration
  123. * @param pattern begin of the formatting pattern
  124. * @param pat_end end of the formatting pattern
  125. *
  126. * Requires: [pattern,pat_end) shall be a valid range.
  127. *
  128. * Effects: The function starts by evaluating err = std::ios_base::goodbit.
  129. * It then enters a loop, reading zero or more characters from s at
  130. * each iteration. Unless otherwise specified below, the loop
  131. * terminates when the first of the following conditions holds:
  132. * - The expression pattern == pat_end evaluates to true.
  133. * - The expression err == std::ios_base::goodbit evaluates to false.
  134. * - The expression s == end evaluates to true, in which case the
  135. * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit.
  136. * - The next element of pattern is equal to '%', followed by a conversion
  137. * specifier character, format.
  138. * If the number of elements in the range [pattern,pat_end) is not
  139. * sufficient to unambiguously determine whether the conversion
  140. * specification is complete and valid, the function evaluates
  141. * err = std::ios_base::failbit. Otherwise, the function evaluates
  142. * s = get_value(s, end, ios, err, r) when the conversion specification is 'v' and
  143. * s = get_value(s, end, ios, err, rt) when the conversion specification is 'u'.
  144. * If err == std::ios_base::goodbit holds after
  145. * the evaluation of the expression, the function increments pattern to
  146. * point just past the end of the conversion specification and continues
  147. * looping.
  148. * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in
  149. * which case the function first increments pattern until
  150. * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true,
  151. * then advances s until s == end || !isspace(*s, ios.getloc()) is true,
  152. * and finally resumes looping.
  153. * - The next character read from s matches the element pointed to by
  154. * pattern in a case-insensitive comparison, in which case the function
  155. * evaluates ++pattern, ++s and continues looping. Otherwise, the function
  156. * evaluates err = std::ios_base::failbit.
  157. *
  158. * Once r and rt are retrieved,
  159. * Returns: s
  160. */
  161. template <typename Rep, typename Period>
  162. iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err,
  163. duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const
  164. {
  165. if (std::has_facet<duration_units<CharT> >(ios.getloc()))
  166. {
  167. duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc());
  168. return get(facet, s, end, ios, err, d, pattern, pat_end);
  169. }
  170. else
  171. {
  172. duration_units_default<CharT> facet;
  173. return get(facet, s, end, ios, err, d, pattern, pat_end);
  174. }
  175. }
  176. template <typename Rep, typename Period>
  177. iter_type get(duration_units<CharT> const&facet, iter_type s, iter_type end, std::ios_base& ios,
  178. std::ios_base::iostate& err, duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const
  179. {
  180. typedef typename detail::duration_io_intermediate<Rep>::type intermediate_type;
  181. intermediate_type r;
  182. rt_ratio rt;
  183. bool value_found = false, unit_found = false;
  184. const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc());
  185. while (pattern != pat_end && err == std::ios_base::goodbit)
  186. {
  187. if (s == end)
  188. {
  189. err |= std::ios_base::eofbit;
  190. break;
  191. }
  192. if (ct.narrow(*pattern, 0) == '%')
  193. {
  194. if (++pattern == pat_end)
  195. {
  196. err |= std::ios_base::failbit;
  197. return s;
  198. }
  199. char cmd = ct.narrow(*pattern, 0);
  200. switch (cmd)
  201. {
  202. case 'v':
  203. {
  204. if (value_found)
  205. {
  206. err |= std::ios_base::failbit;
  207. return s;
  208. }
  209. value_found = true;
  210. s = get_value(s, end, ios, err, r);
  211. if (err & (std::ios_base::badbit | std::ios_base::failbit))
  212. {
  213. return s;
  214. }
  215. break;
  216. }
  217. case 'u':
  218. {
  219. if (unit_found)
  220. {
  221. err |= std::ios_base::failbit;
  222. return s;
  223. }
  224. unit_found = true;
  225. s = get_unit(facet, s, end, ios, err, rt);
  226. if (err & (std::ios_base::badbit | std::ios_base::failbit))
  227. {
  228. return s;
  229. }
  230. break;
  231. }
  232. default:
  233. BOOST_ASSERT(false && "Boost::Chrono internal error.");
  234. break;
  235. }
  236. ++pattern;
  237. }
  238. else if (ct.is(std::ctype_base::space, *pattern))
  239. {
  240. for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern)
  241. ;
  242. for (; s != end && ct.is(std::ctype_base::space, *s); ++s)
  243. ;
  244. }
  245. else if (ct.toupper(*s) == ct.toupper(*pattern))
  246. {
  247. ++s;
  248. ++pattern;
  249. }
  250. else
  251. {
  252. err |= std::ios_base::failbit;
  253. return s;
  254. }
  255. }
  256. unsigned long long num = rt.num;
  257. unsigned long long den = rt.den;
  258. // r should be multiplied by (num/den) / Period
  259. // Reduce (num/den) / Period to lowest terms
  260. unsigned long long gcd_n1_n2 = integer::gcd<unsigned long long>(num, Period::num);
  261. unsigned long long gcd_d1_d2 = integer::gcd<unsigned long long>(den, Period::den);
  262. num /= gcd_n1_n2;
  263. den /= gcd_d1_d2;
  264. unsigned long long n2 = Period::num / gcd_n1_n2;
  265. unsigned long long d2 = Period::den / gcd_d1_d2;
  266. if (num > (std::numeric_limits<unsigned long long>::max)() / d2 || den
  267. > (std::numeric_limits<unsigned long long>::max)() / n2)
  268. {
  269. // (num/den) / Period overflows
  270. err |= std::ios_base::failbit;
  271. return s;
  272. }
  273. num *= d2;
  274. den *= n2;
  275. typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
  276. // num / den is now factor to multiply by r
  277. if (!detail::reduce(r, den, err)) return s;
  278. if (chrono::detail::gt(r, ( (duration_values<common_type_t>::max)() / num)))
  279. {
  280. // Conversion to Period overflowed
  281. err |= std::ios_base::failbit;
  282. return s;
  283. }
  284. common_type_t t = r * num;
  285. t /= den;
  286. if (t > duration_values<common_type_t>::zero())
  287. {
  288. if ( (duration_values<Rep>::max)() < Rep(t))
  289. {
  290. // Conversion to Period overflowed
  291. err |= std::ios_base::failbit;
  292. return s;
  293. }
  294. }
  295. // Success! Store it.
  296. d = duration<Rep, Period> (Rep(t));
  297. return s;
  298. }
  299. /**
  300. *
  301. * @param s start input stream iterator
  302. * @param end end input stream iterator
  303. * @param ios a reference to a ios_base
  304. * @param err the ios_base state
  305. * @param d the duration
  306. * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if
  307. * @code
  308. * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size());
  309. * @codeend
  310. * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
  311. */
  312. template <typename Rep, typename Period>
  313. iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err,
  314. duration<Rep, Period> & d) const
  315. {
  316. if (std::has_facet<duration_units<CharT> >(ios.getloc()))
  317. {
  318. duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc());
  319. std::basic_string<CharT> str = facet.get_pattern();
  320. return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size());
  321. }
  322. else
  323. {
  324. duration_units_default<CharT> facet;
  325. std::basic_string<CharT> str = facet.get_pattern();
  326. return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size());
  327. }
  328. }
  329. /**
  330. *
  331. * @param s start input stream iterator
  332. * @param end end input stream iterator
  333. * @param ios a reference to a ios_base
  334. * @param err the ios_base state
  335. * @param r a reference to the duration representation.
  336. * @Effects As if
  337. * @code
  338. * return std::use_facet<std::num_get<cahr_type, iter_type> >(ios.getloc()).get(s, end, ios, err, r);
  339. * @endcode
  340. *
  341. * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
  342. */
  343. template <typename Rep>
  344. iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, Rep& r) const
  345. {
  346. return std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r);
  347. }
  348. template <typename Rep>
  349. iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, process_times<Rep>& r) const
  350. {
  351. if (s == end) {
  352. err |= std::ios_base::eofbit;
  353. return s;
  354. } else if (*s != '{') { // mandatory '{'
  355. err |= std::ios_base::failbit;
  356. return s;
  357. }
  358. ++s;
  359. s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.real);
  360. if (s == end) {
  361. err |= std::ios_base::eofbit;
  362. return s;
  363. } else if (*s != ';') { // mandatory ';'
  364. err |= std::ios_base::failbit;
  365. return s;
  366. }
  367. ++s;
  368. s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.user);
  369. if (s == end) {
  370. err |= std::ios_base::eofbit;
  371. return s;
  372. } else if (*s != ';') { // mandatory ';'
  373. err |= std::ios_base::failbit;
  374. return s;
  375. }
  376. ++s;
  377. s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.system);
  378. if (s == end) {
  379. err |= std::ios_base::eofbit;
  380. return s;
  381. } else if (*s != '}') { // mandatory '}'
  382. err |= std::ios_base::failbit;
  383. return s;
  384. }
  385. return s;
  386. }
  387. /**
  388. *
  389. * @param s start input stream iterator
  390. * @param e end input stream iterator
  391. * @param ios a reference to a ios_base
  392. * @param err the ios_base state
  393. * @param rt a reference to the duration run-time ratio.
  394. * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
  395. */
  396. iter_type get_unit(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, rt_ratio &rt) const
  397. {
  398. if (std::has_facet<duration_units<CharT> >(is.getloc()))
  399. {
  400. return get_unit(std::use_facet<duration_units<CharT> >(is.getloc()), i, e, is, err, rt);
  401. }
  402. else
  403. {
  404. duration_units_default<CharT> facet;
  405. return get_unit(facet, i, e, is, err, rt);
  406. }
  407. }
  408. iter_type get_unit(duration_units<CharT> const &facet, iter_type i, iter_type e, std::ios_base& is,
  409. std::ios_base::iostate& err, rt_ratio &rt) const
  410. {
  411. if (*i == '[')
  412. {
  413. // parse [N/D]s or [N/D]second or [N/D]seconds format
  414. ++i;
  415. i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.num);
  416. if ( (err & std::ios_base::failbit) != 0)
  417. {
  418. return i;
  419. }
  420. if (i == e)
  421. {
  422. err |= std::ios_base::failbit;
  423. return i;
  424. }
  425. CharT x = *i++;
  426. if (x != '/')
  427. {
  428. err |= std::ios_base::failbit;
  429. return i;
  430. }
  431. i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.den);
  432. if ( (err & std::ios_base::failbit) != 0)
  433. {
  434. return i;
  435. }
  436. if (i == e)
  437. {
  438. err |= std::ios_base::failbit;
  439. return i;
  440. }
  441. if (*i != ']')
  442. {
  443. err |= std::ios_base::failbit;
  444. return i;
  445. }
  446. ++i;
  447. if (i == e)
  448. {
  449. err |= std::ios_base::failbit;
  450. return i;
  451. }
  452. // parse s or second or seconds
  453. return do_get_n_d_valid_unit(facet, i, e, is, err);
  454. }
  455. else
  456. {
  457. return do_get_valid_unit(facet, i, e, is, err, rt);
  458. }
  459. }
  460. /**
  461. * Unique identifier for this type of facet.
  462. */
  463. static std::locale::id id;
  464. /**
  465. * @Effects Destroy the facet
  466. */
  467. ~duration_get()
  468. {
  469. }
  470. protected:
  471. /**
  472. * Extracts the run-time ratio associated to the duration when it is given in prefix form.
  473. *
  474. * This is an extension point of this facet so that we can take in account other periods that can have a useful
  475. * translation in other contexts, as e.g. days and weeks.
  476. *
  477. * @param facet the duration_units facet
  478. * @param i start input stream iterator.
  479. * @param e end input stream iterator.
  480. * @param ios a reference to a ios_base.
  481. * @param err the ios_base state.
  482. * @return @c s
  483. */
  484. iter_type do_get_n_d_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e,
  485. std::ios_base&, std::ios_base::iostate& err) const
  486. {
  487. // parse SI name, short or long
  488. const string_type* units = facet.get_n_d_valid_units_start();
  489. const string_type* units_end = facet.get_n_d_valid_units_end();
  490. const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end,
  491. //~ std::use_facet<std::ctype<CharT> >(loc),
  492. err);
  493. if (err & (std::ios_base::badbit | std::ios_base::failbit))
  494. {
  495. return i;
  496. }
  497. if (!facet.match_n_d_valid_unit(k))
  498. {
  499. err |= std::ios_base::failbit;
  500. }
  501. return i;
  502. }
  503. /**
  504. * Extracts the run-time ratio associated to the duration when it is given in prefix form.
  505. *
  506. * This is an extension point of this facet so that we can take in account other periods that can have a useful
  507. * translation in other contexts, as e.g. days and weeks.
  508. *
  509. * @param facet the duration_units facet
  510. * @param i start input stream iterator.
  511. * @param e end input stream iterator.
  512. * @param ios a reference to a ios_base.
  513. * @param err the ios_base state.
  514. * @param rt a reference to the duration run-time ratio.
  515. * @Effects
  516. * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name.
  517. */
  518. iter_type do_get_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e,
  519. std::ios_base&, std::ios_base::iostate& err, rt_ratio &rt) const
  520. {
  521. // parse SI name, short or long
  522. const string_type* units = facet.get_valid_units_start();
  523. const string_type* units_end = facet.get_valid_units_end();
  524. err = std::ios_base::goodbit;
  525. const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end,
  526. //~ std::use_facet<std::ctype<CharT> >(loc),
  527. err);
  528. if (err & (std::ios_base::badbit | std::ios_base::failbit))
  529. {
  530. return i;
  531. }
  532. if (!facet.match_valid_unit(k, rt))
  533. {
  534. err |= std::ios_base::failbit;
  535. }
  536. return i;
  537. }
  538. };
  539. /**
  540. * Unique identifier for this type of facet.
  541. */
  542. template <class CharT, class InputIterator>
  543. std::locale::id duration_get<CharT, InputIterator>::id;
  544. } // chrono
  545. }
  546. // boost
  547. #endif // header