Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:47

0001 //  (C) Copyright Howard Hinnant
0002 //  (C) Copyright 2011 Vicente J. Botet Escriba
0003 //  Use, modification and distribution are subject to the Boost Software License,
0004 //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 //  http://www.boost.org/LICENSE_1_0.txt).
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  * Duration formatting facet for input.
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         // Reduce r * num / den
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           // Conversion to Period is integral and not exact
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      * @c duration_get is used to parse a character sequence, extracting
0083      * components of a duration into a class duration.
0084      * Each get member parses a format as produced by a corresponding format specifier to time_put<>::put.
0085      * If the sequence being parsed matches the correct format, the
0086      * corresponding member of the class duration argument are set to the
0087      * value used to produce the sequence;
0088      * otherwise either an error is reported or unspecified values are assigned.
0089      * In other words, user confirmation is required for reliable parsing of
0090      * user-entered durations, but machine-generated formats can be parsed
0091      * reliably. This allows parsers to be aggressive about interpreting user
0092      * variations on standard formats.
0093      *
0094      * If the end iterator is reached during parsing of the get() member
0095      * function, the member sets std::ios_base::eofbit in err.
0096      */
0097     template <class CharT, class InputIterator = std::istreambuf_iterator<CharT> >
0098     class duration_get: public std::locale::facet
0099     {
0100     public:
0101       /**
0102        * Type of character the facet is instantiated on.
0103        */
0104       typedef CharT char_type;
0105       /**
0106        * Type of character string passed to member functions.
0107        */
0108       typedef std::basic_string<CharT> string_type;
0109       /**
0110        * Type of iterator used to scan the character buffer.
0111        */
0112       typedef InputIterator iter_type;
0113 
0114       /**
0115        * Construct a @c duration_get facet.
0116        * @param refs
0117        * @Effects Construct a @c duration_get facet.
0118        * If the @c refs argument is @c 0 then destruction of the object is
0119        * delegated to the @c locale, or locales, containing it. This allows
0120        * the user to ignore lifetime management issues. On the other had,
0121        * if @c refs is @c 1 then the object must be explicitly deleted;
0122        * the @c locale will not do so. In this case, the object can be
0123        * maintained across the lifetime of multiple locales.
0124        */
0125 
0126       explicit duration_get(size_t refs = 0) :
0127         std::locale::facet(refs)
0128       {
0129       }
0130 
0131       /**
0132        * @param s start input stream iterator
0133        * @param end end input stream iterator
0134        * @param ios a reference to a ios_base
0135        * @param err the ios_base state
0136        * @param d the duration
0137        * @param pattern begin of the formatting pattern
0138        * @param pat_end end of the formatting pattern
0139        *
0140        * Requires: [pattern,pat_end) shall be a valid range.
0141        *
0142        * Effects: The function starts by evaluating err = std::ios_base::goodbit.
0143        * It then enters a loop, reading zero or more characters from s at
0144        * each iteration. Unless otherwise specified below, the loop
0145        * terminates when the first of the following conditions holds:
0146        * - The expression pattern == pat_end evaluates to true.
0147        * - The expression err == std::ios_base::goodbit evaluates to false.
0148        * - The expression s == end evaluates to true, in which case the
0149        * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit.
0150        * - The next element of pattern is equal to '%', followed by a conversion
0151        * specifier character, format.
0152        * If the number of elements in the range [pattern,pat_end) is not
0153        * sufficient to unambiguously determine whether the conversion
0154        * specification is complete and valid, the function evaluates
0155        * err = std::ios_base::failbit. Otherwise, the function evaluates
0156        * s = get_value(s, end, ios, err, r) when the conversion specification is 'v' and
0157        * s = get_value(s, end, ios, err, rt) when the conversion specification is 'u'.
0158        * If err == std::ios_base::goodbit holds after
0159        * the evaluation of the expression, the function increments pattern to
0160        * point just past the end of the conversion specification and continues
0161        * looping.
0162        * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in
0163        * which case the function first increments pattern until
0164        * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true,
0165        * then advances s until s == end || !isspace(*s, ios.getloc()) is true,
0166        * and finally resumes looping.
0167        * - The next character read from s matches the element pointed to by
0168        * pattern in a case-insensitive comparison, in which case the function
0169        * evaluates ++pattern, ++s and continues looping. Otherwise, the function
0170        * evaluates err = std::ios_base::failbit.
0171        *
0172        * Once r and rt are retrieved,
0173        * Returns: s
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         // r should be multiplied by (num/den) / Period
0280         // Reduce (num/den) / Period to lowest terms
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           // (num/den) / Period overflows
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         // num / den is now factor to multiply by r
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           // Conversion to Period overflowed
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             // Conversion to Period overflowed
0315             err |= std::ios_base::failbit;
0316             return s;
0317           }
0318         }
0319         // Success!  Store it.
0320         d = duration<Rep, Period> (Rep(t));
0321 
0322         return s;
0323       }
0324 
0325       /**
0326        *
0327        * @param s start input stream iterator
0328        * @param end end input stream iterator
0329        * @param ios a reference to a ios_base
0330        * @param err the ios_base state
0331        * @param d the duration
0332        * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if
0333        * @code
0334        *   return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size());
0335        * @codeend
0336        * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
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        * @param s start input stream iterator
0359        * @param end end input stream iterator
0360        * @param ios a reference to a ios_base
0361        * @param err the ios_base state
0362        * @param r a reference to the duration representation.
0363        * @Effects As if
0364        * @code
0365        * return std::use_facet<std::num_get<cahr_type, iter_type> >(ios.getloc()).get(s, end, ios, err, r);
0366        * @endcode
0367        *
0368        * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
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 != '{') { // mandatory '{'
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 != ';') { // mandatory ';'
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 != ';') { // mandatory ';'
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 != '}') { // mandatory '}'
0409             err |= std::ios_base::failbit;
0410             return s;
0411         }
0412         return s;
0413       }
0414 
0415       /**
0416        *
0417        * @param s start input stream iterator
0418        * @param e end input stream iterator
0419        * @param ios a reference to a ios_base
0420        * @param err the ios_base state
0421        * @param rt a reference to the duration run-time ratio.
0422        * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name
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           // parse [N/D]s or [N/D]second or [N/D]seconds format
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           // parse s or second or seconds
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        * Unique identifier for this type of facet.
0495        */
0496       static std::locale::id id;
0497 
0498       /**
0499        * @Effects Destroy the facet
0500        */
0501       ~duration_get()
0502       {
0503       }
0504 
0505     protected:
0506 
0507       /**
0508        * Extracts the run-time ratio associated to the duration when it is given in prefix form.
0509        *
0510        * This is an extension point of this facet so that we can take in account other periods that can have a useful
0511        * translation in other contexts, as e.g. days and weeks.
0512        *
0513        * @param facet the duration_units facet
0514        * @param i start input stream iterator.
0515        * @param e end input stream iterator.
0516        * @param ios a reference to a ios_base.
0517        * @param err the ios_base state.
0518        * @return @c s
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         // parse SI name, short or long
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         //~ std::use_facet<std::ctype<CharT> >(loc),
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        * Extracts the run-time ratio associated to the duration when it is given in prefix form.
0544        *
0545        * This is an extension point of this facet so that we can take in account other periods that can have a useful
0546        * translation in other contexts, as e.g. days and weeks.
0547        *
0548        * @param facet the duration_units facet
0549        * @param i start input stream iterator.
0550        * @param e end input stream iterator.
0551        * @param ios a reference to a ios_base.
0552        * @param err the ios_base state.
0553        * @param rt a reference to the duration run-time ratio.
0554        * @Effects
0555        * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name.
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         // parse SI name, short or long
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         //~ std::use_facet<std::ctype<CharT> >(loc),
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      * Unique identifier for this type of facet.
0583      */
0584     template <class CharT, class InputIterator>
0585     std::locale::id duration_get<CharT, InputIterator>::id;
0586 
0587   } // chrono
0588 }
0589 // boost
0590 
0591 #endif  // header