Chris@16: Chris@16: // chrono_io Chris@16: // Chris@16: // (C) Copyright Howard Hinnant Chris@16: // (C) Copyright 2010 Vicente J. Botet Escriba Chris@16: // Use, modification and distribution are subject to the Boost Software License, Chris@16: // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt). Chris@16: // Chris@16: // This code was adapted by Vicente from Howard Hinnant's experimental work Chris@16: // on chrono i/o under lvm/libc++ to Boost Chris@16: Chris@16: #ifndef BOOST_CHRONO_IO_V1_CHRONO_IO_HPP Chris@16: #define BOOST_CHRONO_IO_V1_CHRONO_IO_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@101: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: Chris@16: namespace chrono Chris@16: { Chris@16: Chris@16: template Chris@16: class duration_punct Chris@16: : public std::locale::facet Chris@16: { Chris@16: public: Chris@16: typedef std::basic_string string_type; Chris@16: enum {use_long, use_short}; Chris@16: Chris@16: private: Chris@16: bool use_short_; Chris@16: string_type long_seconds_; Chris@16: string_type long_minutes_; Chris@16: string_type long_hours_; Chris@16: string_type short_seconds_; Chris@16: string_type short_minutes_; Chris@16: string_type short_hours_; Chris@16: Chris@16: template Chris@16: string_type short_name(Period) const Chris@16: {return ::boost::ratio_string::short_name() + short_seconds_;} Chris@16: Chris@16: string_type short_name(ratio<1>) const {return short_seconds_;} Chris@16: string_type short_name(ratio<60>) const {return short_minutes_;} Chris@16: string_type short_name(ratio<3600>) const {return short_hours_;} Chris@16: Chris@16: template Chris@16: string_type long_name(Period) const Chris@16: {return ::boost::ratio_string::long_name() + long_seconds_;} Chris@16: Chris@16: string_type long_name(ratio<1>) const {return long_seconds_;} Chris@16: string_type long_name(ratio<60>) const {return long_minutes_;} Chris@16: string_type long_name(ratio<3600>) const {return long_hours_;} Chris@16: Chris@16: void init_C(); Chris@16: public: Chris@16: static std::locale::id id; Chris@16: Chris@16: explicit duration_punct(int use = use_long) Chris@16: : use_short_(use==use_short) {init_C();} Chris@16: Chris@16: duration_punct(int use, Chris@16: const string_type& long_seconds, const string_type& long_minutes, Chris@16: const string_type& long_hours, const string_type& short_seconds, Chris@16: const string_type& short_minutes, const string_type& short_hours); Chris@16: Chris@16: duration_punct(int use, const duration_punct& d); Chris@16: Chris@16: template Chris@16: string_type short_name() const Chris@16: {return short_name(typename Period::type());} Chris@16: Chris@16: template Chris@16: string_type long_name() const Chris@16: {return long_name(typename Period::type());} Chris@16: Chris@16: template Chris@16: string_type plural() const Chris@16: {return long_name(typename Period::type());} Chris@16: Chris@16: template Chris@16: string_type singular() const Chris@16: { Chris@16: return string_type(long_name(typename Period::type()), 0, long_name(typename Period::type()).size()-1); Chris@16: } Chris@16: Chris@16: template Chris@16: string_type name() const Chris@16: { Chris@16: if (use_short_) return short_name(); Chris@16: else { Chris@16: return long_name(); Chris@16: } Chris@16: } Chris@16: template Chris@16: string_type name(D v) const Chris@16: { Chris@16: if (use_short_) return short_name(); Chris@16: else Chris@16: { Chris@16: if (v==-1 || v==1) Chris@16: return singular(); Chris@16: else Chris@16: return plural(); Chris@16: } Chris@16: } Chris@16: Chris@16: bool is_short_name() const {return use_short_;} Chris@16: bool is_long_name() const {return !use_short_;} Chris@16: }; Chris@16: Chris@16: template Chris@16: std::locale::id Chris@16: duration_punct::id; Chris@16: Chris@16: template Chris@16: void Chris@16: duration_punct::init_C() Chris@16: { Chris@16: short_seconds_ = CharT('s'); Chris@16: short_minutes_ = CharT('m'); Chris@16: short_hours_ = CharT('h'); Chris@16: const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'}; Chris@16: const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'}; Chris@16: const CharT h[] = {'h', 'o', 'u', 'r', 's'}; Chris@16: long_seconds_.assign(s, s + sizeof(s)/sizeof(s[0])); Chris@16: long_minutes_.assign(m, m + sizeof(m)/sizeof(m[0])); Chris@16: long_hours_.assign(h, h + sizeof(h)/sizeof(h[0])); Chris@16: } Chris@16: Chris@16: template Chris@16: duration_punct::duration_punct(int use, Chris@16: const string_type& long_seconds, const string_type& long_minutes, Chris@16: const string_type& long_hours, const string_type& short_seconds, Chris@16: const string_type& short_minutes, const string_type& short_hours) Chris@16: : use_short_(use==use_short), Chris@16: long_seconds_(long_seconds), Chris@16: long_minutes_(long_minutes), Chris@16: long_hours_(long_hours), Chris@16: short_seconds_(short_seconds), Chris@16: short_minutes_(short_minutes), Chris@16: short_hours_(short_hours) Chris@16: {} Chris@16: Chris@16: template Chris@16: duration_punct::duration_punct(int use, const duration_punct& d) Chris@16: : use_short_(use==use_short), Chris@16: long_seconds_(d.long_seconds_), Chris@16: long_minutes_(d.long_minutes_), Chris@16: long_hours_(d.long_hours_), Chris@16: short_seconds_(d.short_seconds_), Chris@16: short_minutes_(d.short_minutes_), Chris@16: short_hours_(d.short_hours_) Chris@16: {} Chris@16: Chris@16: template Chris@16: std::basic_ostream& Chris@16: duration_short(std::basic_ostream& os) Chris@16: { Chris@16: typedef duration_punct Facet; Chris@16: std::locale loc = os.getloc(); Chris@16: if (std::has_facet(loc)) Chris@16: { Chris@16: const Facet& f = std::use_facet(loc); Chris@16: if (f.is_long_name()) Chris@16: os.imbue(std::locale(loc, new Facet(Facet::use_short, f))); Chris@16: } Chris@16: else Chris@16: os.imbue(std::locale(loc, new Facet(Facet::use_short))); Chris@16: return os; Chris@16: } Chris@16: Chris@16: template Chris@16: std::basic_ostream& Chris@16: duration_long(std::basic_ostream& os) Chris@16: { Chris@16: typedef duration_punct Facet; Chris@16: std::locale loc = os.getloc(); Chris@16: if (std::has_facet(loc)) Chris@16: { Chris@16: const Facet& f = std::use_facet(loc); Chris@16: if (f.is_short_name()) Chris@16: os.imbue(std::locale(loc, new Facet(Facet::use_long, f))); Chris@16: } Chris@16: return os; Chris@16: } Chris@16: Chris@16: template Chris@16: std::basic_ostream& Chris@16: operator<<(std::basic_ostream& os, const duration& d) Chris@16: { Chris@16: typedef duration_punct Facet; Chris@16: std::locale loc = os.getloc(); Chris@16: if (!std::has_facet(loc)) Chris@16: os.imbue(std::locale(loc, new Facet)); Chris@16: const Facet& f = std::use_facet(os.getloc()); Chris@16: return os << d.count() << ' ' << f.template name(d.count()); Chris@16: } Chris@16: Chris@16: namespace chrono_detail { Chris@16: template ::value> Chris@16: struct duration_io_intermediate Chris@16: { Chris@16: typedef Rep type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct duration_io_intermediate Chris@16: { Chris@16: typedef typename mpl::if_c Chris@16: < Chris@16: is_floating_point::value, Chris@16: long double, Chris@16: typename mpl::if_c Chris@16: < Chris@16: is_signed::value, Chris@16: long long, Chris@16: unsigned long long Chris@16: >::type Chris@16: >::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: typename enable_if, bool>::type Chris@16: reduce(intermediate_type& r, unsigned long long& den, std::ios_base::iostate& err) Chris@16: { Chris@16: typedef typename common_type::type common_type_t; Chris@16: Chris@16: // Reduce r * num / den Chris@101: common_type_t t = integer::gcd(common_type_t(r), common_type_t(den)); Chris@16: r /= t; Chris@16: den /= t; Chris@16: if (den != 1) Chris@16: { Chris@16: // Conversion to Period is integral and not exact Chris@16: err |= std::ios_base::failbit; Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: template Chris@16: typename disable_if, bool>::type Chris@16: reduce(intermediate_type& , unsigned long long& , std::ios_base::iostate& ) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@16: } Chris@16: Chris@16: template Chris@16: std::basic_istream& Chris@16: operator>>(std::basic_istream& is, duration& d) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: typedef duration_punct Facet; Chris@16: std::locale loc = is.getloc(); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: if (!std::has_facet(loc)) { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.imbue(std::locale(loc, new Facet)); Chris@16: } Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: loc = is.getloc(); Chris@16: const Facet& f = std::use_facet(loc); Chris@16: typedef typename chrono_detail::duration_io_intermediate::type intermediate_type; Chris@16: intermediate_type r; Chris@16: std::ios_base::iostate err = std::ios_base::goodbit; Chris@16: // read value into r Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is >> r; Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: if (is.good()) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // now determine unit Chris@16: typedef std::istreambuf_iterator in_iterator; Chris@16: in_iterator i(is); Chris@16: in_iterator e; Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: if (i != e && *i == ' ') // mandatory ' ' after value Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: ++i; Chris@16: if (i != e) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // unit is num / den (yet to be determined) Chris@16: unsigned long long num = 0; Chris@16: unsigned long long den = 0; Chris@16: if (*i == '[') Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // parse [N/D]s or [N/D]seconds format Chris@16: ++i; Chris@16: CharT x; Chris@16: is >> num >> x >> den; Chris@16: if (!is.good() || (x != '/')) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(is.failbit); Chris@16: return is; Chris@16: } Chris@16: i = in_iterator(is); Chris@16: if (*i != ']') Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(is.failbit); Chris@16: return is; Chris@16: } Chris@16: ++i; Chris@16: const std::basic_string units[] = Chris@16: { Chris@16: f.template singular >(), Chris@16: f.template plural >(), Chris@16: f.template short_name >() Chris@16: }; Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: const std::basic_string* k = chrono_detail::scan_keyword(i, e, Chris@16: units, units + sizeof(units)/sizeof(units[0]), Chris@16: //~ std::use_facet >(loc), Chris@16: err); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(err); Chris@16: switch ((k - units) / 3) Chris@16: { Chris@16: case 0: Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: break; Chris@16: default: Chris@16: is.setstate(err); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: return is; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // parse SI name, short or long Chris@16: const std::basic_string units[] = Chris@16: { Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular(), Chris@16: f.template plural(), Chris@16: f.template short_name(), Chris@16: f.template singular >(), Chris@16: f.template plural >(), Chris@16: f.template short_name >(), Chris@16: f.template singular >(), Chris@16: f.template plural >(), Chris@16: f.template short_name >(), Chris@16: f.template singular >(), Chris@16: f.template plural >(), Chris@16: f.template short_name >() Chris@16: }; Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: const std::basic_string* k = chrono_detail::scan_keyword(i, e, Chris@16: units, units + sizeof(units)/sizeof(units[0]), Chris@16: //~ std::use_facet >(loc), Chris@16: err); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: switch ((k - units) / 3) Chris@16: { Chris@16: case 0: Chris@16: num = 1ULL; Chris@16: den = 1000000000000000000ULL; Chris@16: break; Chris@16: case 1: Chris@16: num = 1ULL; Chris@16: den = 1000000000000000ULL; Chris@16: break; Chris@16: case 2: Chris@16: num = 1ULL; Chris@16: den = 1000000000000ULL; Chris@16: break; Chris@16: case 3: Chris@16: num = 1ULL; Chris@16: den = 1000000000ULL; Chris@16: break; Chris@16: case 4: Chris@16: num = 1ULL; Chris@16: den = 1000000ULL; Chris@16: break; Chris@16: case 5: Chris@16: num = 1ULL; Chris@16: den = 1000ULL; Chris@16: break; Chris@16: case 6: Chris@16: num = 1ULL; Chris@16: den = 100ULL; Chris@16: break; Chris@16: case 7: Chris@16: num = 1ULL; Chris@16: den = 10ULL; Chris@16: break; Chris@16: case 8: Chris@16: num = 10ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 9: Chris@16: num = 100ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 10: Chris@16: num = 1000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 11: Chris@16: num = 1000000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 12: Chris@16: num = 1000000000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 13: Chris@16: num = 1000000000000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 14: Chris@16: num = 1000000000000000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 15: Chris@16: num = 1000000000000000000ULL; Chris@16: den = 1ULL; Chris@16: break; Chris@16: case 16: Chris@16: num = 1; Chris@16: den = 1; Chris@16: break; Chris@16: case 17: Chris@16: num = 60; Chris@16: den = 1; Chris@16: break; Chris@16: case 18: Chris@16: num = 3600; Chris@16: den = 1; Chris@16: break; Chris@16: default: Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(err|is.failbit); Chris@16: return is; Chris@16: } Chris@16: } Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // unit is num/den Chris@16: // r should be multiplied by (num/den) / Period Chris@16: // Reduce (num/den) / Period to lowest terms Chris@101: unsigned long long gcd_n1_n2 = integer::gcd(num, Period::num); Chris@101: unsigned long long gcd_d1_d2 = integer::gcd(den, Period::den); Chris@16: num /= gcd_n1_n2; Chris@16: den /= gcd_d1_d2; Chris@16: unsigned long long n2 = Period::num / gcd_n1_n2; Chris@16: unsigned long long d2 = Period::den / gcd_d1_d2; Chris@16: if (num > (std::numeric_limits::max)() / d2 || Chris@16: den > (std::numeric_limits::max)() / n2) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // (num/den) / Period overflows Chris@16: is.setstate(err|is.failbit); Chris@16: return is; Chris@16: } Chris@16: num *= d2; Chris@16: den *= n2; Chris@16: Chris@16: typedef typename common_type::type common_type_t; Chris@16: Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // num / den is now factor to multiply by r Chris@16: if (!chrono_detail::reduce(r, den, err)) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(err|is.failbit); Chris@16: return is; Chris@16: } Chris@16: Chris@16: //if (r > ((duration_values::max)() / num)) Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: if (chrono::detail::gt(r,((duration_values::max)() / num))) Chris@16: { Chris@16: // Conversion to Period overflowed Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(err|is.failbit); Chris@16: return is; Chris@16: } Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: common_type_t t = r * num; Chris@16: t /= den; Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: Chris@101: if (t > duration_values::zero()) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: Rep pt = t; Chris@16: if ( (duration_values::max)() < pt) Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // Conversion to Period overflowed Chris@16: is.setstate(err|is.failbit); Chris@16: return is; Chris@16: } Chris@16: } Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: // Success! Store it. Chris@16: r = Rep(t); Chris@16: d = duration(r); Chris@16: is.setstate(err); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: return is; Chris@16: } Chris@16: else { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: is.setstate(is.failbit | is.eofbit); Chris@16: return is; Chris@16: } Chris@16: } Chris@16: else Chris@16: { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: if (i == e) Chris@16: is.setstate(is.failbit|is.eofbit); Chris@16: else Chris@16: is.setstate(is.failbit); Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: return is; Chris@16: } Chris@16: } Chris@16: else { Chris@16: //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; Chris@16: //is.setstate(is.failbit); Chris@16: return is; Chris@16: } Chris@16: } Chris@16: Chris@16: Chris@16: template Chris@16: std::basic_ostream& Chris@16: operator<<(std::basic_ostream& os, Chris@16: const time_point& tp) Chris@16: { Chris@16: return os << tp.time_since_epoch() << clock_string::since(); Chris@16: } Chris@16: Chris@16: template Chris@16: std::basic_istream& Chris@16: operator>>(std::basic_istream& is, Chris@16: time_point& tp) Chris@16: { Chris@16: Duration d; Chris@16: is >> d; Chris@16: if (is.good()) Chris@16: { Chris@16: const std::basic_string units=clock_string::since(); Chris@16: std::ios_base::iostate err = std::ios_base::goodbit; Chris@16: typedef std::istreambuf_iterator in_iterator; Chris@16: in_iterator i(is); Chris@16: in_iterator e; Chris@16: std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, Chris@16: &units, &units + 1, Chris@16: //~ std::use_facet >(is.getloc()), Chris@16: err) - &units; Chris@16: is.setstate(err); Chris@16: if (k == 1) Chris@16: { Chris@16: is.setstate(err | is.failbit); Chris@16: // failed to read epoch string Chris@16: return is; Chris@16: } Chris@16: tp = time_point(d); Chris@16: } Chris@16: else Chris@16: is.setstate(is.failbit); Chris@16: return is; Chris@16: } Chris@16: } // chrono Chris@16: Chris@16: } Chris@16: Chris@16: #endif // BOOST_CHRONO_CHRONO_IO_HPP