Created
March 7, 2016 18:00
-
-
Save Nava2/bdf4bb751be2953e3340 to your computer and use it in GitHub Desktop.
IO for std::chrono that prints nice messages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// chrono_io | |
// | |
// (C) Copyright Howard Hinnant | |
// Use, modification and distribution are subject to the Boost Software License, | |
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt). | |
#ifndef _CHRONO_IO | |
#define _CHRONO_IO | |
/* | |
chrono_io synopsis | |
#include <chrono> | |
#include <ratio_io> | |
namespace std | |
{ | |
namespace chrono | |
{ | |
template <class CharT> | |
class durationpunct | |
: public locale::facet | |
{ | |
public: | |
static locale::id id; | |
typedef basic_string<CharT> string_type; | |
enum {use_long, use_short}; | |
explicit durationpunct(int use = use_long); | |
durationpunct(int use, | |
const string_type& long_seconds, const string_type& long_minutes, | |
const string_type& long_hours, const string_type& short_seconds, | |
const string_type& short_minutes, const string_type& short_hours); | |
durationpunct(int use, const durationpunct& d); | |
template <class Period> string_type short_name() const; | |
template <class Period> string_type long_name() const; | |
template <class Period> string_type name() const; | |
bool is_short_name() const; | |
bool is_long_name() const; | |
}; | |
template <class CharT, class Traits> | |
basic_ostream<CharT, Traits>& | |
duration_short(basic_ostream<CharT, Traits>& os); | |
template <class CharT, class Traits> | |
basic_ostream<CharT, Traits>& | |
duration_long(basic_ostream<CharT, Traits>& os); | |
template <class CharT, class Traits, class Rep, class Period> | |
basic_ostream<CharT, Traits>& | |
operator<<(basic_ostream<CharT, Traits>& os, const duration<Rep, Period>& d); | |
template <class CharT, class Traits, class Rep, class Period> | |
basic_istream<CharT, Traits>& | |
operator>>(basic_istream<CharT, Traits>& is, duration<Rep, Period>& d); | |
template <class CharT, class Traits, class Duration> | |
basic_ostream<CharT, Traits>& | |
operator<<(basic_ostream<CharT, Traits>& os, | |
const time_point<steady_clock, Duration>& tp); | |
template <class CharT, class Traits, class Duration> | |
basic_ostream<CharT, Traits>& | |
operator<<(basic_ostream<CharT, Traits>& os, | |
const time_point<high_resolution_clock, Duration>& tp); | |
template <class CharT, class Traits, class Duration> | |
basic_ostream<CharT, Traits>& | |
operator<<(basic_ostream<CharT, Traits>& os, | |
const time_point<system_clock, Duration>& tp); | |
template <class CharT, class Traits, class Duration> | |
basic_istream<CharT, Traits>& | |
operator>>(basic_istream<CharT, Traits>& is, | |
time_point<steady_clock, Duration>& tp); | |
template <class CharT, class Traits, class Duration> | |
basic_istream<CharT, Traits>& | |
operator>>(basic_istream<CharT, Traits>& is, | |
time_point<high_resolution_clock, Duration>& tp); | |
template <class CharT, class Traits, class Duration> | |
basic_istream<CharT, Traits>& | |
operator>>(basic_istream<CharT, Traits>& is, | |
time_point<system_clock, Duration>& tp); | |
template <class CharT> | |
class timepunct | |
: public std::locale::facet | |
{ | |
public: | |
typedef std::basic_string<CharT> string_type; | |
static std::locale::id id; | |
explicit timepunct(std::size_t refs = 0, | |
const string_type& fmt = string_type(), | |
bool local = false); | |
explicit timepunct(std::size_t refs, | |
string_type&& fmt, | |
bool local = false); | |
const string_type& fmt() const {return fmt_;} | |
bool local() const {return local_;} | |
}; | |
template<class CharT> | |
unspecfiied | |
local_fmt(std::basic_string<CharT> fmt = std::basic_string<CharT>()); | |
template<class CharT> | |
unspecfiied | |
local_fmt(const CharT* fmt); | |
template<class CharT> | |
unspecfiied | |
utc_fmt(std::basic_string<CharT> fmt = std::basic_string<CharT>()); | |
template<class CharT> | |
unspecfiied | |
utc_fmt(const CharT* fmt); | |
} // chrono | |
} // std | |
*/ | |
#include <chrono> | |
#include <locale> | |
#include "ratio_io" | |
namespace std | |
{ | |
namespace chrono | |
{ | |
template <class To, class Rep, class Period> | |
To | |
round(const duration<Rep, Period>& d) | |
{ | |
To t0 = duration_cast<To>(d); | |
To t1 = t0; | |
++t1; | |
typedef typename common_type<To, duration<Rep, Period> >::type _D; | |
_D diff0 = d - t0; | |
_D diff1 = t1 - d; | |
if (diff0 == diff1) | |
{ | |
if (t0.count() & 1) | |
return t1; | |
return t0; | |
} | |
else if (diff0 < diff1) | |
return t0; | |
return t1; | |
} | |
template <class _CharT> | |
class durationpunct | |
: public locale::facet | |
{ | |
public: | |
typedef basic_string<_CharT> string_type; | |
enum {use_long, use_short}; | |
private: | |
bool __use_short_; | |
string_type __seconds_; | |
string_type __minutes_; | |
string_type __hours_; | |
public: | |
static locale::id id; | |
explicit durationpunct(size_t refs = 0, | |
int __use = use_long) | |
: locale::facet(refs), __use_short_(__use) {} | |
durationpunct(size_t refs, int __use, | |
string_type __seconds, string_type __minutes, | |
string_type __hours) | |
: locale::facet(refs), __use_short_(__use), | |
__seconds_(std::move(__seconds)), | |
__minutes_(std::move(__minutes)), | |
__hours_(std::move(__hours)) {} | |
bool is_short_name() const {return __use_short_;} | |
bool is_long_name() const {return !__use_short_;} | |
string_type seconds() const {return __seconds_;} | |
string_type minutes() const {return __minutes_;} | |
string_type hours() const {return __hours_;} | |
}; | |
template <class _CharT> | |
locale::id | |
durationpunct<_CharT>::id; | |
enum {prefix, symbol}; | |
enum {utc, local}; | |
template<class _CharT> | |
struct __duration_manip | |
{ | |
bool __use_short_; | |
basic_string<_CharT> __seconds_; | |
basic_string<_CharT> __minutes_; | |
basic_string<_CharT> __hours_; | |
__duration_manip(bool __use_short, basic_string<_CharT> __seconds, | |
basic_string<_CharT> __minutes, basic_string<_CharT> __hours) | |
: __use_short_(__use_short), | |
__seconds_(std::move(__seconds)), | |
__minutes_(std::move(__minutes)), | |
__hours_(std::move(__hours)) {} | |
}; | |
class duration_fmt | |
{ | |
int form_; | |
public: | |
explicit duration_fmt(int f) : form_(f) {} | |
// explicit | |
operator int() const {return form_;} | |
}; | |
template<class charT, class traits> | |
std::basic_ostream<charT, traits>& | |
operator <<(std::basic_ostream<charT, traits>& os, duration_fmt d) | |
{ | |
os.imbue(std::locale(os.getloc(), new durationpunct<charT>(0, d == symbol))); | |
return os; | |
} | |
template<class charT, class traits> | |
std::basic_istream<charT, traits>& | |
operator >>(std::basic_istream<charT, traits>& is, duration_fmt d) | |
{ | |
is.imbue(std::locale(is.getloc(), new durationpunct<charT>(0, d == symbol))); | |
return is; | |
} | |
template<class charT, class traits> | |
std::basic_ostream<charT, traits>& | |
operator <<(std::basic_ostream<charT, traits>& os, __duration_manip<charT> m) | |
{ | |
os.imbue(std::locale(os.getloc(), new durationpunct<charT>(0, m.__use_short_, | |
std::move(m.__seconds_), std::move(m.__minutes_), std::move(m.__hours_)))); | |
return os; | |
} | |
template<class charT, class traits> | |
std::basic_istream<charT, traits>& | |
operator >>(std::basic_istream<charT, traits>& is, __duration_manip<charT> m) | |
{ | |
is.imbue(std::locale(is.getloc(), new durationpunct<charT>(0, m.__use_short_, | |
std::move(m.__seconds_), std::move(m.__minutes_), std::move(m.__hours_)))); | |
return is; | |
} | |
inline | |
__duration_manip<char> | |
duration_short() | |
{ | |
return __duration_manip<char>(durationpunct<char>::use_short, "", "", ""); | |
} | |
template <class _CharT> | |
inline | |
__duration_manip<_CharT> | |
duration_short(basic_string<_CharT> __seconds, | |
basic_string<_CharT> __minutes, | |
basic_string<_CharT> __hours) | |
{ | |
return __duration_manip<_CharT>(durationpunct<_CharT>::use_short, | |
std::move(__seconds), std::move(__minutes), | |
std::move(__hours)); | |
} | |
inline | |
__duration_manip<char> | |
duration_long() | |
{ | |
return __duration_manip<char>(durationpunct<char>::use_long, "", "", ""); | |
} | |
template <class _CharT, class _T2, class _T3> | |
inline | |
typename enable_if | |
< | |
is_convertible<_T2, basic_string<_CharT> >::value && | |
is_convertible<_T3, basic_string<_CharT> >::value, | |
__duration_manip<_CharT> | |
>::type | |
duration_long(basic_string<_CharT> __seconds, | |
_T2 __minutes, | |
_T3 __hours) | |
{ | |
typedef basic_string<_CharT> string_type; | |
return __duration_manip<_CharT>(durationpunct<_CharT>::use_long, | |
std::move(__seconds), | |
string_type(std::move(__minutes)), | |
string_type(std::move(__hours))); | |
} | |
template <class _CharT, class _T2, class _T3> | |
inline | |
typename enable_if | |
< | |
is_convertible<_T2, basic_string<_CharT> >::value && | |
is_convertible<_T3, basic_string<_CharT> >::value, | |
__duration_manip<_CharT> | |
>::type | |
duration_long(const _CharT* __seconds, | |
_T2 __minutes, | |
_T3 __hours) | |
{ | |
typedef basic_string<_CharT> string_type; | |
return __duration_manip<_CharT>(durationpunct<_CharT>::use_long, | |
string_type(__seconds), | |
string_type(std::move(__minutes)), | |
string_type(std::move(__hours))); | |
} | |
template <class _CharT, class _Period> | |
basic_string<_CharT> | |
__get_unit(bool __is_long, const basic_string<_CharT>& __seconds, | |
const basic_string<_CharT>&, const basic_string<_CharT>&, _Period) | |
{ | |
if (__is_long) | |
{ | |
if (__seconds.empty()) | |
{ | |
_CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's', 0}; | |
return ratio_string<_Period, _CharT>::prefix() + __p; | |
} | |
return ratio_string<_Period, _CharT>::prefix() + __seconds; | |
} | |
if (__seconds.empty()) | |
return ratio_string<_Period, _CharT>::symbol() + 's'; | |
return ratio_string<_Period, _CharT>::symbol() + __seconds; | |
} | |
template <class _CharT> | |
inline | |
basic_string<_CharT> | |
__get_unit(bool __is_long, const basic_string<_CharT>& __seconds, | |
const basic_string<_CharT>&, const basic_string<_CharT>&, ratio<1>) | |
{ | |
if (__seconds.empty()) | |
{ | |
if (__is_long) | |
{ | |
_CharT __p[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'}; | |
return basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT)); | |
} | |
else | |
return basic_string<_CharT>(1, 's'); | |
} | |
return __seconds; | |
} | |
template <class _CharT> | |
basic_string<_CharT> | |
__get_unit(bool __is_long, const basic_string<_CharT>&, | |
const basic_string<_CharT>& __minutes, | |
const basic_string<_CharT>&, ratio<60>) | |
{ | |
if (__minutes.empty()) | |
{ | |
if (__is_long) | |
{ | |
_CharT __p[] = {'m', 'i', 'n', 'u', 't', 'e', 's'}; | |
return basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT)); | |
} | |
else | |
return basic_string<_CharT>(1, 'm'); | |
} | |
return __minutes; | |
} | |
template <class _CharT> | |
inline | |
basic_string<_CharT> | |
__get_unit(bool __is_long, const basic_string<_CharT>&, | |
const basic_string<_CharT>&, | |
const basic_string<_CharT>& __hours, ratio<3600>) | |
{ | |
if (__hours.empty()) | |
{ | |
if (__is_long) | |
{ | |
_CharT __p[] = {'h', 'o', 'u', 'r', 's'}; | |
return basic_string<_CharT>(__p, __p + sizeof(__p) / sizeof(_CharT)); | |
} | |
else | |
return basic_string<_CharT>(1, 'h'); | |
} | |
return __hours; | |
} | |
template <class _CharT, class _Traits, class _Rep, class _Period> | |
basic_ostream<_CharT, _Traits>& | |
operator<<(basic_ostream<_CharT, _Traits>& __os, const duration<_Rep, _Period>& __d) | |
{ | |
typename basic_ostream<_CharT, _Traits>::sentry ok(__os); | |
if (ok) | |
{ | |
typedef durationpunct<_CharT> _F; | |
typedef basic_string<_CharT> string_type; | |
bool failed = false; | |
try | |
{ | |
bool __is_long = true; | |
string_type __seconds; | |
string_type __minutes; | |
string_type __hours; | |
locale __loc = __os.getloc(); | |
if (has_facet<_F>(__loc)) | |
{ | |
const _F& f = use_facet<_F>(__loc); | |
__is_long = f.is_long_name(); | |
__seconds = f.seconds(); | |
__minutes = f.minutes(); | |
__hours = f.hours(); | |
} | |
string_type __unit = __get_unit(__is_long, __seconds, __minutes, | |
__hours, typename _Period::type()); | |
__os << __d.count() << ' ' << __unit; | |
} | |
catch (...) | |
{ | |
failed = true; | |
} | |
if (failed) | |
__os.setstate(ios_base::failbit | ios_base::badbit); | |
} | |
return __os; | |
} | |
template <class _Rep, bool = is_scalar<_Rep>::value> | |
struct __duration_io_intermediate | |
{ | |
typedef _Rep type; | |
}; | |
template <class _Rep> | |
struct __duration_io_intermediate<_Rep, true> | |
{ | |
typedef typename conditional | |
< | |
is_floating_point<_Rep>::value, | |
long double, | |
typename conditional | |
< | |
is_signed<_Rep>::value, | |
long long, | |
unsigned long long | |
>::type | |
>::type type; | |
}; | |
template <class T> | |
T | |
__gcd(T x, T y) | |
{ | |
while (y != 0) | |
{ | |
T old_x = x; | |
x = y; | |
y = old_x % y; | |
} | |
return x; | |
} | |
template <> | |
long double | |
inline | |
__gcd(long double x, long double y) | |
{ | |
return 1; | |
} | |
template <class _CharT, class _Traits, class _Rep, class _Period> | |
basic_istream<_CharT, _Traits>& | |
operator>>(basic_istream<_CharT, _Traits>& __is, duration<_Rep, _Period>& __d) | |
{ | |
typedef basic_string<_CharT> string_type; | |
typedef durationpunct<_CharT> _F; | |
typedef typename __duration_io_intermediate<_Rep>::type _IR; | |
_IR __r; | |
// read value into __r | |
__is >> __r; | |
if (__is.good()) | |
{ | |
// now determine unit | |
typedef istreambuf_iterator<_CharT, _Traits> _I; | |
_I __i(__is); | |
_I __e; | |
if (__i != __e && *__i == ' ') // mandatory ' ' after value | |
{ | |
++__i; | |
if (__i != __e) | |
{ | |
string_type __seconds; | |
string_type __minutes; | |
string_type __hours; | |
locale __loc = __is.getloc(); | |
if (has_facet<_F>(__loc)) | |
{ | |
const _F& f = use_facet<_F>(__loc); | |
__seconds = f.seconds(); | |
__minutes = f.minutes(); | |
__hours = f.hours(); | |
} | |
// unit is num / den (yet to be determined) | |
unsigned long long num = 0; | |
unsigned long long den = 0; | |
if (*__i == '[') | |
{ | |
// parse [N/D]s or [N/D]seconds format | |
++__i; | |
_CharT __x; | |
__is >> num >> __x >> den; | |
if (!__is.good() || __x != '/') | |
{ | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
__i = _I(__is); | |
if (*__i != ']') | |
{ | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
++__i; | |
const basic_string<_CharT> __units[] = | |
{ | |
__get_unit(true, __seconds, __minutes, __hours, ratio<1>()), | |
__get_unit(false, __seconds, __minutes, __hours, ratio<1>()) | |
}; | |
ios_base::iostate __err = ios_base::goodbit; | |
const basic_string<_CharT>* __k = __scan_keyword(__i, __e, | |
__units, __units + sizeof(__units)/sizeof(__units[0]), | |
use_facet<ctype<_CharT> >(__loc), | |
__err); | |
switch ((__k - __units) / 2) | |
{ | |
case 0: | |
break; | |
default: | |
__is.setstate(__err); | |
return __is; | |
} | |
} | |
else | |
{ | |
// parse SI name, short or long | |
const basic_string<_CharT> __units[] = | |
{ | |
__get_unit(true, __seconds, __minutes, __hours, atto()), | |
__get_unit(false, __seconds, __minutes, __hours, atto()), | |
__get_unit(true, __seconds, __minutes, __hours, femto()), | |
__get_unit(false, __seconds, __minutes, __hours, femto()), | |
__get_unit(true, __seconds, __minutes, __hours, pico()), | |
__get_unit(false, __seconds, __minutes, __hours, pico()), | |
__get_unit(true, __seconds, __minutes, __hours, nano()), | |
__get_unit(false, __seconds, __minutes, __hours, nano()), | |
__get_unit(true, __seconds, __minutes, __hours, micro()), | |
__get_unit(false, __seconds, __minutes, __hours, micro()), | |
__get_unit(true, __seconds, __minutes, __hours, milli()), | |
__get_unit(false, __seconds, __minutes, __hours, milli()), | |
__get_unit(true, __seconds, __minutes, __hours, centi()), | |
__get_unit(false, __seconds, __minutes, __hours, centi()), | |
__get_unit(true, __seconds, __minutes, __hours, deci()), | |
__get_unit(false, __seconds, __minutes, __hours, deci()), | |
__get_unit(true, __seconds, __minutes, __hours, deca()), | |
__get_unit(false, __seconds, __minutes, __hours, deca()), | |
__get_unit(true, __seconds, __minutes, __hours, hecto()), | |
__get_unit(false, __seconds, __minutes, __hours, hecto()), | |
__get_unit(true, __seconds, __minutes, __hours, kilo()), | |
__get_unit(false, __seconds, __minutes, __hours, kilo()), | |
__get_unit(true, __seconds, __minutes, __hours, mega()), | |
__get_unit(false, __seconds, __minutes, __hours, mega()), | |
__get_unit(true, __seconds, __minutes, __hours, giga()), | |
__get_unit(false, __seconds, __minutes, __hours, giga()), | |
__get_unit(true, __seconds, __minutes, __hours, tera()), | |
__get_unit(false, __seconds, __minutes, __hours, tera()), | |
__get_unit(true, __seconds, __minutes, __hours, peta()), | |
__get_unit(false, __seconds, __minutes, __hours, peta()), | |
__get_unit(true, __seconds, __minutes, __hours, exa()), | |
__get_unit(false, __seconds, __minutes, __hours, exa()), | |
__get_unit(true, __seconds, __minutes, __hours, ratio<1>()), | |
__get_unit(false, __seconds, __minutes, __hours, ratio<1>()), | |
__get_unit(true, __seconds, __minutes, __hours, ratio<60>()), | |
__get_unit(false, __seconds, __minutes, __hours, ratio<60>()), | |
__get_unit(true, __seconds, __minutes, __hours, ratio<3600>()), | |
__get_unit(false, __seconds, __minutes, __hours, ratio<3600>()) | |
}; | |
ios_base::iostate __err = ios_base::goodbit; | |
const basic_string<_CharT>* __k = __scan_keyword(__i, __e, | |
__units, __units + sizeof(__units)/sizeof(__units[0]), | |
use_facet<ctype<_CharT> >(__loc), | |
__err); | |
switch ((__k - __units) / 2) | |
{ | |
case 0: | |
num = 1ULL; | |
den = 1000000000000000000ULL; | |
break; | |
case 1: | |
num = 1ULL; | |
den = 1000000000000000ULL; | |
break; | |
case 2: | |
num = 1ULL; | |
den = 1000000000000ULL; | |
break; | |
case 3: | |
num = 1ULL; | |
den = 1000000000ULL; | |
break; | |
case 4: | |
num = 1ULL; | |
den = 1000000ULL; | |
break; | |
case 5: | |
num = 1ULL; | |
den = 1000ULL; | |
break; | |
case 6: | |
num = 1ULL; | |
den = 100ULL; | |
break; | |
case 7: | |
num = 1ULL; | |
den = 10ULL; | |
break; | |
case 8: | |
num = 10ULL; | |
den = 1ULL; | |
break; | |
case 9: | |
num = 100ULL; | |
den = 1ULL; | |
break; | |
case 10: | |
num = 1000ULL; | |
den = 1ULL; | |
break; | |
case 11: | |
num = 1000000ULL; | |
den = 1ULL; | |
break; | |
case 12: | |
num = 1000000000ULL; | |
den = 1ULL; | |
break; | |
case 13: | |
num = 1000000000000ULL; | |
den = 1ULL; | |
break; | |
case 14: | |
num = 1000000000000000ULL; | |
den = 1ULL; | |
break; | |
case 15: | |
num = 1000000000000000000ULL; | |
den = 1ULL; | |
break; | |
case 16: | |
num = 1; | |
den = 1; | |
break; | |
case 17: | |
num = 60; | |
den = 1; | |
break; | |
case 18: | |
num = 3600; | |
den = 1; | |
break; | |
default: | |
__is.setstate(__err); | |
return __is; | |
} | |
} | |
// unit is num/den | |
// __r should be multiplied by (num/den) / _Period | |
// Reduce (num/den) / _Period to lowest terms | |
unsigned long long __gcd_n1_n2 = __gcd<unsigned long long>(num, _Period::num); | |
unsigned long long __gcd_d1_d2 = __gcd<unsigned long long>(den, _Period::den); | |
num /= __gcd_n1_n2; | |
den /= __gcd_d1_d2; | |
unsigned long long __n2 = _Period::num / __gcd_n1_n2; | |
unsigned long long __d2 = _Period::den / __gcd_d1_d2; | |
if (num > numeric_limits<unsigned long long>::max() / __d2 || | |
den > numeric_limits<unsigned long long>::max() / __n2) | |
{ | |
// (num/den) / _Period overflows | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
num *= __d2; | |
den *= __n2; | |
// num / den is now factor to multiply by __r | |
typedef typename common_type<_IR, unsigned long long>::type _CT; | |
if (is_integral<_IR>::value) | |
{ | |
// Reduce __r * num / den | |
_CT __t = __gcd<_CT>(__r, den); | |
__r /= __t; | |
den /= __t; | |
if (den != 1) | |
{ | |
// Conversion to _Period is integral and not exact | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
} | |
if (__r > duration_values<_CT>::max() / num) | |
{ | |
// Conversion to _Period overflowed | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
_CT __t = __r * num; | |
__t /= den; | |
if (duration_values<_Rep>::max() < __t) | |
{ | |
// Conversion to _Period overflowed | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
// Success! Store it. | |
__r = _Rep(__t); | |
__d = duration<_Rep, _Period>(__r); | |
} | |
else | |
__is.setstate(__is.failbit | __is.eofbit); | |
} | |
else | |
{ | |
if (__i == __e) | |
__is.setstate(__is.eofbit); | |
__is.setstate(__is.failbit); | |
} | |
} | |
else | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
template <class charT> | |
class timepunct | |
: public std::locale::facet | |
{ | |
public: | |
typedef std::basic_string<charT> string_type; | |
private: | |
string_type fmt_; | |
bool local_; | |
public: | |
static std::locale::id id; | |
explicit timepunct(std::size_t refs = 0, | |
const string_type& fmt = string_type(), | |
bool local = false) | |
: std::locale::facet(refs), | |
fmt_(fmt), | |
local_(local) {} | |
explicit timepunct(std::size_t refs, | |
string_type&& fmt, | |
bool local = false) | |
: std::locale::facet(refs), | |
fmt_(std::move(fmt)), | |
local_(local) {} | |
const string_type& fmt() const {return fmt_;} | |
bool local() const {return local_;} | |
}; | |
template <class CharT> | |
std::locale::id | |
timepunct<CharT>::id; | |
template <class _CharT, class _Traits, class _Duration> | |
basic_ostream<_CharT, _Traits>& | |
operator<<(basic_ostream<_CharT, _Traits>& __os, | |
const time_point<steady_clock, _Duration>& __tp) | |
{ | |
return __os << __tp.time_since_epoch() << " since boot"; | |
} | |
template<class charT> | |
struct __time_manip | |
{ | |
std::basic_string<charT> fmt_; | |
bool local_; | |
__time_manip(std::basic_string<charT> fmt, bool local) | |
: fmt_(std::move(fmt)), | |
local_(local) {} | |
}; | |
template<class charT, class traits> | |
std::basic_ostream<charT, traits>& | |
operator <<(std::basic_ostream<charT, traits>& os, __time_manip<charT> m) | |
{ | |
os.imbue(std::locale(os.getloc(), new timepunct<charT>(0, std::move(m.fmt_), m.local_))); | |
return os; | |
} | |
template<class charT, class traits> | |
std::basic_istream<charT, traits>& | |
operator >>(std::basic_istream<charT, traits>& is, __time_manip<charT> m) | |
{ | |
is.imbue(std::locale(is.getloc(), new timepunct<charT>(0, std::move(m.fmt_), m.local_))); | |
return is; | |
} | |
template<class charT> | |
inline | |
__time_manip<charT> | |
local_fmt(std::basic_string<charT> fmt) | |
{ | |
return __time_manip<charT>(std::move(fmt), true); | |
} | |
template<class charT> | |
inline | |
__time_manip<charT> | |
local_fmt(const charT* fmt) | |
{ | |
return __time_manip<charT>(fmt, true); | |
} | |
inline | |
__time_manip<char> | |
local_fmt() | |
{ | |
return __time_manip<char>("", true); | |
} | |
template<class charT> | |
inline | |
__time_manip<charT> | |
utc_fmt(std::basic_string<charT> fmt) | |
{ | |
return __time_manip<charT>(std::move(fmt), false); | |
} | |
template<class charT> | |
inline | |
__time_manip<charT> | |
utc_fmt(const charT* fmt) | |
{ | |
return __time_manip<charT>(fmt, false); | |
} | |
inline | |
__time_manip<char> | |
utc_fmt() | |
{ | |
return __time_manip<char>("", false); | |
} | |
class __time_man | |
{ | |
int form_; | |
public: | |
explicit __time_man(int f) : form_(f) {} | |
// explicit | |
operator int() const {return form_;} | |
}; | |
template<class charT, class traits> | |
std::basic_ostream<charT, traits>& | |
operator <<(std::basic_ostream<charT, traits>& os, __time_man m) | |
{ | |
os.imbue(std::locale(os.getloc(), new timepunct<charT>(0, basic_string<charT>(), m == local))); | |
return os; | |
} | |
template<class charT, class traits> | |
std::basic_istream<charT, traits>& | |
operator >>(std::basic_istream<charT, traits>& is, __time_man m) | |
{ | |
is.imbue(std::locale(is.getloc(), new timepunct<charT>(0, basic_string<charT>(), m == local))); | |
return is; | |
} | |
inline | |
__time_man | |
time_fmt(int f) | |
{ | |
return __time_man(f); | |
} | |
template <class _CharT, class _Traits, class _Duration> | |
basic_istream<_CharT, _Traits>& | |
operator>>(basic_istream<_CharT, _Traits>& __is, | |
time_point<steady_clock, _Duration>& __tp) | |
{ | |
_Duration __d; | |
__is >> __d; | |
if (__is.good()) | |
{ | |
const _CharT __u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't'}; | |
const basic_string<_CharT> __units(__u, __u + sizeof(__u)/sizeof(__u[0])); | |
ios_base::iostate __err = ios_base::goodbit; | |
typedef istreambuf_iterator<_CharT, _Traits> _I; | |
_I __i(__is); | |
_I __e; | |
ptrdiff_t __k = __scan_keyword(__i, __e, | |
&__units, &__units + 1, | |
use_facet<ctype<_CharT> >(__is.getloc()), | |
__err) - &__units; | |
if (__k == 1) | |
{ | |
// failed to read epoch string | |
__is.setstate(__err); | |
return __is; | |
} | |
__tp = time_point<steady_clock, _Duration>(__d); | |
} | |
else | |
__is.setstate(__is.failbit); | |
return __is; | |
} | |
template <class _CharT, class _Traits, class _Duration> | |
basic_ostream<_CharT, _Traits>& | |
operator<<(basic_ostream<_CharT, _Traits>& __os, | |
const time_point<system_clock, _Duration>& __tp) | |
{ | |
typename basic_ostream<_CharT, _Traits>::sentry ok(__os); | |
if (ok) | |
{ | |
bool failed = false; | |
try | |
{ | |
const _CharT* pb = nullptr; | |
const _CharT* pe = pb; | |
bool __local = false; | |
typedef timepunct<_CharT> F; | |
locale loc = __os.getloc(); | |
if (has_facet<F>(loc)) | |
{ | |
const F& f = use_facet<F>(loc); | |
pb = f.fmt().data(); | |
pe = pb + f.fmt().size(); | |
__local = f.local(); | |
} | |
time_t __t = system_clock::to_time_t(__tp); | |
tm __tm; | |
if (__local) | |
{ | |
if (localtime_r(&__t, &__tm) == 0) | |
failed = true; | |
} | |
else | |
{ | |
if (gmtime_r(&__t, &__tm) == 0) | |
failed = true; | |
} | |
if (!failed) | |
{ | |
const time_put<_CharT>& tp = use_facet<time_put<_CharT> >(loc); | |
if (pb == pe) | |
{ | |
_CharT pattern[] = {'%', 'F', ' ', '%', 'H', ':', '%', 'M', ':'}; | |
pb = pattern; | |
pe = pb + sizeof(pattern) / sizeof(_CharT); | |
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed(); | |
if (!failed) | |
{ | |
duration<double> __d = __tp - system_clock::from_time_t(__t) + | |
seconds(__tm.tm_sec); | |
if (__d.count() < 10) | |
__os << _CharT('0'); | |
ios::fmtflags __flgs = __os.flags(); | |
__os.setf(ios::fixed, ios::floatfield); | |
__os << __d.count(); | |
__os.flags(__flgs); | |
if (__local) | |
{ | |
_CharT sub_pattern[] = {' ', '%', 'z'}; | |
pb = sub_pattern; | |
pe = pb + + sizeof(sub_pattern) / sizeof(_CharT); | |
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed(); | |
} | |
else | |
{ | |
_CharT sub_pattern[] = {' ', '+', '0', '0', '0', '0', 0}; | |
__os << sub_pattern; | |
} | |
} | |
} | |
else | |
failed = tp.put(__os, __os, __os.fill(), &__tm, pb, pe).failed(); | |
} | |
} | |
catch (...) | |
{ | |
failed = true; | |
} | |
if (failed) | |
__os.setstate(ios_base::failbit | ios_base::badbit); | |
} | |
return __os; | |
} | |
template <class _CharT, class _Traits, class _Duration> | |
basic_istream<_CharT, _Traits>& | |
operator>>(basic_istream<_CharT, _Traits>& __is, | |
time_point<system_clock, _Duration>& __tp) | |
{ | |
typename basic_istream<_CharT,_Traits>::sentry ok(__is); | |
if (ok) | |
{ | |
ios_base::iostate err = ios_base::goodbit; | |
try | |
{ | |
const _CharT* pb = nullptr; | |
const _CharT* pe = pb; | |
bool __local = false; | |
typedef timepunct<_CharT> F; | |
locale loc = __is.getloc(); | |
if (has_facet<F>(loc)) | |
{ | |
const F& f = use_facet<F>(loc); | |
pb = f.fmt().data(); | |
pe = pb + f.fmt().size(); | |
__local = f.local(); | |
} | |
const time_get<_CharT>& tg = use_facet<time_get<_CharT> >(loc); | |
tm __tm = {0}; | |
if (pb == pe) | |
{ | |
_CharT pattern[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd', | |
' ', '%', 'H', ':', '%', 'M', ':'}; | |
pb = pattern; | |
pe = pb + sizeof(pattern) / sizeof(_CharT); | |
tg.get(__is, 0, __is, err, &__tm, pb, pe); | |
if (err & ios_base::failbit) | |
goto __exit; | |
typedef istreambuf_iterator<_CharT, _Traits> _I; | |
double __sec; | |
_CharT __c = _CharT(); | |
__is >> __sec; | |
if (__is.fail()) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
_I __i(__is); | |
_I __eof; | |
__c = *__i; | |
if (++__i == __eof || __c != ' ') | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
__c = *__i; | |
if (++__i == __eof || (__c != '+' && __c != '-')) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
int __n = __c == '-' ? 1 : -1; | |
__c = *__i; | |
if (++__i == __eof || !isdigit(__c)) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
int __min = (__c - '0') * 600; | |
__c = *__i; | |
if (++__i == __eof || !isdigit(__c)) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
__min += (__c - '0') * 60; | |
__c = *__i; | |
if (++__i == __eof || !isdigit(__c)) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
__min += (__c - '0') * 10; | |
__c = *__i; | |
if (!isdigit(__c)) | |
{ | |
err |= ios_base::failbit; | |
goto __exit; | |
} | |
++__i; | |
__min += __c - '0'; | |
__min *= __n; | |
time_t __t; | |
__t = timegm(&__tm); | |
__tp = system_clock::from_time_t(__t) + minutes(__min) | |
+ round<microseconds>(duration<double>(__sec)); | |
} | |
else | |
{ | |
tg.get(__is, 0, __is, err, &__tm, pb, pe); | |
} | |
} | |
catch (...) | |
{ | |
err |= ios_base::badbit | ios_base::failbit; | |
} | |
__exit: | |
__is.setstate(err); | |
} | |
return __is; | |
} | |
} // chrono | |
} // std | |
#endif // _CHRONO_IO |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment