File indexing completed on 2025-01-18 09:29:47
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_CHRONO_IO_DURATION_GET_HPP
0009 #define BOOST_CHRONO_IO_DURATION_GET_HPP
0010
0011 #include <boost/chrono/config.hpp>
0012 #include <string>
0013 #include <boost/type_traits/is_scalar.hpp>
0014 #include <boost/core/enable_if.hpp>
0015 #include <boost/type_traits/is_signed.hpp>
0016 #include <boost/mpl/if.hpp>
0017 #include <boost/integer/common_factor_rt.hpp>
0018 #include <boost/chrono/detail/scan_keyword.hpp>
0019 #include <boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp>
0020 #include <boost/chrono/process_cpu_clocks.hpp>
0021
0022 #include <boost/assert.hpp>
0023 #include <locale>
0024
0025
0026
0027
0028 namespace boost
0029 {
0030 namespace chrono
0031 {
0032
0033 namespace detail
0034 {
0035 template <class Rep, bool = is_scalar<Rep>::value>
0036 struct duration_io_intermediate
0037 {
0038 typedef Rep type;
0039 };
0040
0041 template <class Rep>
0042 struct duration_io_intermediate<Rep, true>
0043 {
0044 typedef typename mpl::if_c<is_floating_point<Rep>::value, long double, typename mpl::if_c<
0045 is_signed<Rep>::value, long long, unsigned long long>::type>::type type;
0046 };
0047
0048 template <class Rep>
0049 struct duration_io_intermediate<process_times<Rep>, false>
0050 {
0051 typedef process_times<typename duration_io_intermediate<Rep>::type> type;
0052 };
0053
0054 template <typename intermediate_type>
0055 typename enable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type& r,
0056 unsigned long long& den, std::ios_base::iostate& err)
0057 {
0058 typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
0059
0060
0061 common_type_t t = integer::gcd<common_type_t>(common_type_t(r), common_type_t(den));
0062 r /= t;
0063 den /= t;
0064 if (den != 1)
0065 {
0066
0067 err |= std::ios_base::failbit;
0068 return false;
0069 }
0070 return true;
0071 }
0072 template <typename intermediate_type>
0073 typename disable_if<is_integral<intermediate_type> , bool>::type reduce(intermediate_type&, unsigned long long&,
0074 std::ios_base::iostate&)
0075 {
0076 return true;
0077 }
0078
0079 }
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> >
0098 class duration_get: public std::locale::facet
0099 {
0100 public:
0101
0102
0103
0104 typedef CharT char_type;
0105
0106
0107
0108 typedef std::basic_string<CharT> string_type;
0109
0110
0111
0112 typedef InputIterator iter_type;
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 explicit duration_get(size_t refs = 0) :
0127 std::locale::facet(refs)
0128 {
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175 template <typename Rep, typename Period>
0176 iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err,
0177 duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const
0178 {
0179 if (std::has_facet<duration_units<CharT> >(ios.getloc()))
0180 {
0181 duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc());
0182 return get(facet, s, end, ios, err, d, pattern, pat_end);
0183 }
0184 else
0185 {
0186 duration_units_default<CharT> facet;
0187 return get(facet, s, end, ios, err, d, pattern, pat_end);
0188 }
0189 }
0190
0191 template <typename Rep, typename Period>
0192 iter_type get(duration_units<CharT> const&facet, iter_type s, iter_type end, std::ios_base& ios,
0193 std::ios_base::iostate& err, duration<Rep, Period> &d, const char_type *pattern, const char_type *pat_end) const
0194 {
0195
0196 typedef typename detail::duration_io_intermediate<Rep>::type intermediate_type;
0197 intermediate_type r;
0198 rt_ratio rt;
0199 bool value_found = false, unit_found = false;
0200
0201 const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc());
0202 while (pattern != pat_end && err == std::ios_base::goodbit)
0203 {
0204 if (s == end)
0205 {
0206 err |= std::ios_base::eofbit;
0207 break;
0208 }
0209 if (ct.narrow(*pattern, 0) == '%')
0210 {
0211 if (++pattern == pat_end)
0212 {
0213 err |= std::ios_base::failbit;
0214 return s;
0215 }
0216 char cmd = ct.narrow(*pattern, 0);
0217 switch (cmd)
0218 {
0219 case 'v':
0220 {
0221 if (value_found)
0222 {
0223 err |= std::ios_base::failbit;
0224 return s;
0225 }
0226 value_found = true;
0227 s = get_value(s, end, ios, err, r);
0228 if (err & (std::ios_base::badbit | std::ios_base::failbit))
0229 {
0230 return s;
0231 }
0232 break;
0233 }
0234 case 'u':
0235 {
0236 if (unit_found)
0237 {
0238 err |= std::ios_base::failbit;
0239 return s;
0240 }
0241 unit_found = true;
0242 s = get_unit(facet, s, end, ios, err, rt);
0243 if (err & (std::ios_base::badbit | std::ios_base::failbit))
0244 {
0245 return s;
0246 }
0247 break;
0248 }
0249 default:
0250 BOOST_ASSERT(false && "Boost::Chrono internal error.");
0251 break;
0252 }
0253
0254 ++pattern;
0255 }
0256 else if (ct.is(std::ctype_base::space, *pattern))
0257 {
0258 for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern)
0259 ;
0260 for (; s != end && ct.is(std::ctype_base::space, *s); ++s)
0261 ;
0262 }
0263 else if (ct.toupper(*s) == ct.toupper(*pattern))
0264 {
0265 ++s;
0266 ++pattern;
0267 }
0268 else
0269 {
0270 err |= std::ios_base::failbit;
0271 return s;
0272 }
0273
0274 }
0275
0276 unsigned long long num = rt.num;
0277 unsigned long long den = rt.den;
0278
0279
0280
0281 unsigned long long gcd_n1_n2 = integer::gcd<unsigned long long>(num, Period::num);
0282 unsigned long long gcd_d1_d2 = integer::gcd<unsigned long long>(den, Period::den);
0283 num /= gcd_n1_n2;
0284 den /= gcd_d1_d2;
0285 unsigned long long n2 = Period::num / gcd_n1_n2;
0286 unsigned long long d2 = Period::den / gcd_d1_d2;
0287 if (num > (std::numeric_limits<unsigned long long>::max)() / d2 || den
0288 > (std::numeric_limits<unsigned long long>::max)() / n2)
0289 {
0290
0291 err |= std::ios_base::failbit;
0292 return s;
0293 }
0294 num *= d2;
0295 den *= n2;
0296
0297 typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
0298
0299
0300 if (!detail::reduce(r, den, err)) return s;
0301
0302 if (chrono::detail::gt(r, ( (duration_values<common_type_t>::max)() / num)))
0303 {
0304
0305 err |= std::ios_base::failbit;
0306 return s;
0307 }
0308 common_type_t t = r * num;
0309 t /= den;
0310 if (t > duration_values<common_type_t>::zero())
0311 {
0312 if ( (duration_values<Rep>::max)() < Rep(t))
0313 {
0314
0315 err |= std::ios_base::failbit;
0316 return s;
0317 }
0318 }
0319
0320 d = duration<Rep, Period> (Rep(t));
0321
0322 return s;
0323 }
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 template <typename Rep, typename Period>
0339 iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err,
0340 duration<Rep, Period> & d) const
0341 {
0342 if (std::has_facet<duration_units<CharT> >(ios.getloc()))
0343 {
0344 duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(ios.getloc());
0345 std::basic_string<CharT> str = facet.get_pattern();
0346 return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size());
0347 }
0348 else
0349 {
0350 duration_units_default<CharT> facet;
0351 std::basic_string<CharT> str = facet.get_pattern();
0352 return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size());
0353 }
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370 template <typename Rep>
0371 iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, Rep& r) const
0372 {
0373 return std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r);
0374 }
0375 template <typename Rep>
0376 iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, process_times<Rep>& r) const
0377 {
0378 if (s == end) {
0379 err |= std::ios_base::eofbit;
0380 return s;
0381 } else if (*s != '{') {
0382 err |= std::ios_base::failbit;
0383 return s;
0384 }
0385 ++s;
0386 s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.real);
0387 if (s == end) {
0388 err |= std::ios_base::eofbit;
0389 return s;
0390 } else if (*s != ';') {
0391 err |= std::ios_base::failbit;
0392 return s;
0393 }
0394 ++s;
0395 s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.user);
0396 if (s == end) {
0397 err |= std::ios_base::eofbit;
0398 return s;
0399 } else if (*s != ';') {
0400 err |= std::ios_base::failbit;
0401 return s;
0402 }
0403 ++s;
0404 s = std::use_facet<std::num_get<CharT, iter_type> >(ios.getloc()).get(s, end, ios, err, r.system);
0405 if (s == end) {
0406 err |= std::ios_base::eofbit;
0407 return s;
0408 } else if (*s != '}') {
0409 err |= std::ios_base::failbit;
0410 return s;
0411 }
0412 return s;
0413 }
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424 iter_type get_unit(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, rt_ratio &rt) const
0425 {
0426 if (std::has_facet<duration_units<CharT> >(is.getloc()))
0427 {
0428 return get_unit(std::use_facet<duration_units<CharT> >(is.getloc()), i, e, is, err, rt);
0429 }
0430 else
0431 {
0432 duration_units_default<CharT> facet;
0433 return get_unit(facet, i, e, is, err, rt);
0434 }
0435 }
0436
0437
0438 iter_type get_unit(duration_units<CharT> const &facet, iter_type i, iter_type e, std::ios_base& is,
0439 std::ios_base::iostate& err, rt_ratio &rt) const
0440 {
0441
0442 if (*i == '[')
0443 {
0444
0445 ++i;
0446 i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.num);
0447 if ( (err & std::ios_base::failbit) != 0)
0448 {
0449 return i;
0450 }
0451
0452 if (i == e)
0453 {
0454 err |= std::ios_base::failbit;
0455 return i;
0456 }
0457 CharT x = *i++;
0458 if (x != '/')
0459 {
0460 err |= std::ios_base::failbit;
0461 return i;
0462 }
0463 i = std::use_facet<std::num_get<CharT, iter_type> >(is.getloc()).get(i, e, is, err, rt.den);
0464 if ( (err & std::ios_base::failbit) != 0)
0465 {
0466 return i;
0467 }
0468 if (i == e)
0469 {
0470 err |= std::ios_base::failbit;
0471 return i;
0472 }
0473 if (*i != ']')
0474 {
0475 err |= std::ios_base::failbit;
0476 return i;
0477 }
0478 ++i;
0479 if (i == e)
0480 {
0481 err |= std::ios_base::failbit;
0482 return i;
0483 }
0484
0485 return do_get_n_d_valid_unit(facet, i, e, is, err);
0486 }
0487 else
0488 {
0489 return do_get_valid_unit(facet, i, e, is, err, rt);
0490 }
0491 }
0492
0493
0494
0495
0496 static std::locale::id id;
0497
0498
0499
0500
0501 ~duration_get()
0502 {
0503 }
0504
0505 protected:
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520 iter_type do_get_n_d_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e,
0521 std::ios_base&, std::ios_base::iostate& err) const
0522 {
0523
0524
0525 const string_type* units = facet.get_n_d_valid_units_start();
0526 const string_type* units_end = facet.get_n_d_valid_units_end();
0527
0528 const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end,
0529
0530 err);
0531 if (err & (std::ios_base::badbit | std::ios_base::failbit))
0532 {
0533 return i;
0534 }
0535 if (!facet.match_n_d_valid_unit(k))
0536 {
0537 err |= std::ios_base::failbit;
0538 }
0539 return i;
0540 }
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557 iter_type do_get_valid_unit(duration_units<CharT> const &facet, iter_type i, iter_type e,
0558 std::ios_base&, std::ios_base::iostate& err, rt_ratio &rt) const
0559 {
0560
0561
0562 const string_type* units = facet.get_valid_units_start();
0563 const string_type* units_end = facet.get_valid_units_end();
0564
0565 err = std::ios_base::goodbit;
0566 const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end,
0567
0568 err);
0569 if (err & (std::ios_base::badbit | std::ios_base::failbit))
0570 {
0571 return i;
0572 }
0573 if (!facet.match_valid_unit(k, rt))
0574 {
0575 err |= std::ios_base::failbit;
0576 }
0577 return i;
0578 }
0579 };
0580
0581
0582
0583
0584 template <class CharT, class InputIterator>
0585 std::locale::id duration_get<CharT, InputIterator>::id;
0586
0587 }
0588 }
0589
0590
0591 #endif