blob: c65adee663346c5ac81ecc5bd2fe585c08c7876f [file] [log] [blame]
// chrono_io
//
// (C) Copyright Howard Hinnant
// (C) Copyright 2010 Vicente J. Botet Escriba
// 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).
//
// This code was adapted by Vicente from Howard Hinnant's experimental work
// on chrono i/o under lvm/libc++ to Boost
#ifndef BOOST_CHRONO_CHRONO_IO_HPP
#define BOOST_CHRONO_CHRONO_IO_HPP
#include <boost/chrono/chrono.hpp>
#include <boost/chrono/process_cpu_clocks.hpp>
#include <boost/chrono/thread_clock.hpp>
#include <boost/ratio/ratio_io.hpp>
#include <locale>
#include <boost/type_traits/is_scalar.hpp>
#include <boost/type_traits/is_signed.hpp>
#include <boost/mpl/if.hpp>
#include <boost/math/common_factor_rt.hpp>
#include <boost/chrono/detail/scan_keyword.hpp>
namespace boost
{
namespace chrono
{
template <class CharT>
class duration_punct
: public std::locale::facet
{
public:
typedef std::basic_string<CharT> string_type;
enum {use_long, use_short};
private:
bool use_short_;
string_type long_seconds_;
string_type long_minutes_;
string_type long_hours_;
string_type short_seconds_;
string_type short_minutes_;
string_type short_hours_;
template <class Period>
string_type short_name(Period) const
{return ::boost::ratio_string<Period, CharT>::short_name() + short_seconds_;}
string_type short_name(ratio<1>) const {return short_seconds_;}
string_type short_name(ratio<60>) const {return short_minutes_;}
string_type short_name(ratio<3600>) const {return short_hours_;}
template <class Period>
string_type long_name(Period) const
{return ::boost::ratio_string<Period, CharT>::long_name() + long_seconds_;}
string_type long_name(ratio<1>) const {return long_seconds_;}
string_type long_name(ratio<60>) const {return long_minutes_;}
string_type long_name(ratio<3600>) const {return long_hours_;}
void init_C();
public:
static std::locale::id id;
explicit duration_punct(int use = use_long)
: use_short_(use==use_short) {init_C();}
duration_punct(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);
duration_punct(int use, const duration_punct& d);
template <class Period>
string_type short_name() const
{return short_name(typename Period::type());}
template <class Period>
string_type long_name() const
{return long_name(typename Period::type());}
template <class Period>
string_type name() const {
if (use_short_) return short_name<Period>();
else return long_name<Period>();
}
bool is_short_name() const {return use_short_;}
bool is_long_name() const {return !use_short_;}
};
template <class CharT>
std::locale::id
duration_punct<CharT>::id;
template <class CharT>
void
duration_punct<CharT>::init_C()
{
short_seconds_ = CharT('s');
short_minutes_ = CharT('m');
short_hours_ = CharT('h');
const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'};
const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'};
const CharT h[] = {'h', 'o', 'u', 'r', 's'};
long_seconds_.assign(s, s + sizeof(s)/sizeof(s[0]));
long_minutes_.assign(m, m + sizeof(m)/sizeof(m[0]));
long_hours_.assign(h, h + sizeof(h)/sizeof(h[0]));
}
template <class CharT>
duration_punct<CharT>::duration_punct(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)
: use_short_(use==use_short),
long_seconds_(long_seconds),
long_minutes_(long_minutes),
long_hours_(long_hours),
short_seconds_(short_seconds),
short_minutes_(short_minutes),
short_hours_(short_hours)
{}
template <class CharT>
duration_punct<CharT>::duration_punct(int use, const duration_punct& d)
: use_short_(use==use_short),
long_seconds_(d.long_seconds_),
long_minutes_(d.long_minutes_),
long_hours_(d.long_hours_),
short_seconds_(d.short_seconds_),
short_minutes_(d.short_minutes_),
short_hours_(d.short_hours_)
{}
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
duration_short(std::basic_ostream<CharT, Traits>& os)
{
typedef duration_punct<CharT> Facet;
std::locale loc = os.getloc();
if (std::has_facet<Facet>(loc))
{
const Facet& f = std::use_facet<Facet>(loc);
if (f.is_long_name())
os.imbue(std::locale(loc, new Facet(Facet::use_short, f)));
}
else
os.imbue(std::locale(loc, new Facet(Facet::use_short)));
return os;
}
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>&
duration_long(std::basic_ostream<CharT, Traits>& os)
{
typedef duration_punct<CharT> Facet;
std::locale loc = os.getloc();
if (std::has_facet<Facet>(loc))
{
const Facet& f = std::use_facet<Facet>(loc);
if (f.is_short_name())
os.imbue(std::locale(loc, new Facet(Facet::use_long, f)));
}
return os;
}
template <class CharT, class Traits, class Rep, class Period>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const duration<Rep, Period>& d)
{
typedef duration_punct<CharT> Facet;
std::locale loc = os.getloc();
if (!std::has_facet<Facet>(loc))
os.imbue(std::locale(loc, new Facet));
const Facet& f = std::use_facet<Facet>(os.getloc());
return os << d.count() << ' ' << f.template name<Period>();
}
namespace chrono_detail {
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 mpl::if_c
<
is_floating_point<Rep>::value,
long double,
typename mpl::if_c
<
is_signed<Rep>::value,
long long,
unsigned long long
>::type
>::type type;
};
}
template <class CharT, class Traits, class Rep, class Period>
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is, duration<Rep, Period>& d)
{
typedef duration_punct<CharT> Facet;
std::locale loc = is.getloc();
if (!std::has_facet<Facet>(loc))
is.imbue(std::locale(loc, new Facet));
loc = is.getloc();
const Facet& f = std::use_facet<Facet>(loc);
typedef typename chrono_detail::duration_io_intermediate<Rep>::type intermediate_type;
intermediate_type r;
// read value into r
is >> r;
if (is.good())
{
// now determine unit
typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
in_iterator i(is);
in_iterator e;
if (i != e && *i == ' ') // mandatory ' ' after value
{
++i;
if (i != e)
{
// 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 = in_iterator(is);
if (*i != ']')
{
is.setstate(is.failbit);
return is;
}
++i;
const std::basic_string<CharT> units[] =
{
f.template long_name<ratio<1> >(),
f.template short_name<ratio<1> >()
};
std::ios_base::iostate err = std::ios_base::goodbit;
const std::basic_string<CharT>* k = chrono_detail::scan_keyword(i, e,
units, units + sizeof(units)/sizeof(units[0]),
//~ std::use_facet<std::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 std::basic_string<CharT> units[] =
{
f.template long_name<atto>(),
f.template short_name<atto>(),
f.template long_name<femto>(),
f.template short_name<femto>(),
f.template long_name<pico>(),
f.template short_name<pico>(),
f.template long_name<nano>(),
f.template short_name<nano>(),
f.template long_name<micro>(),
f.template short_name<micro>(),
f.template long_name<milli>(),
f.template short_name<milli>(),
f.template long_name<centi>(),
f.template short_name<centi>(),
f.template long_name<deci>(),
f.template short_name<deci>(),
f.template long_name<deca>(),
f.template short_name<deca>(),
f.template long_name<hecto>(),
f.template short_name<hecto>(),
f.template long_name<kilo>(),
f.template short_name<kilo>(),
f.template long_name<mega>(),
f.template short_name<mega>(),
f.template long_name<giga>(),
f.template short_name<giga>(),
f.template long_name<tera>(),
f.template short_name<tera>(),
f.template long_name<peta>(),
f.template short_name<peta>(),
f.template long_name<exa>(),
f.template short_name<exa>(),
f.template long_name<ratio<1> >(),
f.template short_name<ratio<1> >(),
f.template long_name<ratio<60> >(),
f.template short_name<ratio<60> >(),
f.template long_name<ratio<3600> >(),
f.template short_name<ratio<3600> >()
};
std::ios_base::iostate err = std::ios_base::goodbit;
const std::basic_string<CharT>* k = chrono_detail::scan_keyword(i, e,
units, units + sizeof(units)/sizeof(units[0]),
//~ std::use_facet<std::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 = math::gcd<unsigned long long>(num, Period::num);
unsigned long long gcd_d1_d2 = math::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 > (std::numeric_limits<unsigned long long>::max)() / d2 ||
den > (std::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<intermediate_type, unsigned long long>::type common_type_t;
if (is_integral<intermediate_type>::value)
{
// Reduce r * num / den
common_type_t t = math::gcd<common_type_t>(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<common_type_t>::max)() / num))
{
// Conversion to Period overflowed
is.setstate(is.failbit);
return is;
}
common_type_t 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 Clock, class CharT>
struct clock_string;
template <class CharT>
struct clock_string<system_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'s', 'y', 's', 't', 'e', 'm', '_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
static const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'J', 'a',
'n', ' ', '1', ',', ' ', '1', '9', '7', '0'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
template <class CharT>
struct clock_string<steady_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'m', 'o', 'n', 'o', 't', 'o', 'n', 'i', 'c', '_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
#endif
#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK)
template <class CharT>
struct clock_string<thread_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'t', 'h', 'r', 'e', 'd', '_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 't', 'r', 'e', 'a', 'd', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
#endif
template <class CharT>
struct clock_string<process_real_cpu_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'r', 'e', 'a', 'l','_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
template <class CharT>
struct clock_string<process_user_cpu_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'u', 's', 'e', 'r','_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
template <class CharT>
struct clock_string<process_system_cpu_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'p', 'r', 'o', 'c', 'e', 's', 's', '_', 's', 'y', 's', 't', 't', 'e', 'm', '_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
template <class CharT>
struct clock_string<process_cpu_clock, CharT>
{
static std::basic_string<CharT> name()
{
static const CharT u[] = {'p', 'r', 'o', 'c', 'e', 's', 's', '_',
'c', 'l','o', 'c', 'k'};
static const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
static std::basic_string<CharT> since()
{
const CharT u[] = {' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'};
const std::basic_string<CharT> str(u, u + sizeof(u)/sizeof(u[0]));
return str;
}
};
template <class CharT, class Traits, class Clock, class Duration>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const time_point<Clock, Duration>& tp)
{
return os << tp.time_since_epoch() << clock_string<Clock, CharT>::since();
}
template <class CharT, class Traits, class Clock, class Duration>
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
time_point<Clock, Duration>& tp)
{
Duration d;
is >> d;
if (is.good())
{
const std::basic_string<CharT> units=clock_string<Clock, CharT>::since();
std::ios_base::iostate err = std::ios_base::goodbit;
typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
in_iterator i(is);
in_iterator e;
std::ptrdiff_t k = chrono_detail::scan_keyword(i, e,
&units, &units + 1,
//~ std::use_facet<std::ctype<CharT> >(is.getloc()),
err) - &units;
if (k == 1)
{
// failed to read epoch string
is.setstate(err);
return is;
}
tp = time_point<Clock, Duration>(d);
}
else
is.setstate(is.failbit);
return is;
}
} // chrono
}
#endif // BOOST_CHRONO_CHRONO_IO_HPP