4
// (C) Copyright Howard Hinnant
5
// (C) Copyright 2010 Vicente J. Botet Escriba
6
// Use, modification and distribution are subject to the Boost Software License,
7
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8
// http://www.boost.org/LICENSE_1_0.txt).
10
// This code was adapted by Vicente from Howard Hinnant's experimental work
11
// on chrono i/o under lvm/libc++ to Boost
13
#ifndef BOOST_CHRONO_IO_V1_CHRONO_IO_HPP
14
#define BOOST_CHRONO_IO_V1_CHRONO_IO_HPP
16
#include <boost/chrono/chrono.hpp>
17
#include <boost/chrono/process_cpu_clocks.hpp>
18
#include <boost/chrono/thread_clock.hpp>
19
#include <boost/chrono/clock_string.hpp>
20
#include <boost/ratio/ratio_io.hpp>
22
#include <boost/type_traits/is_scalar.hpp>
23
#include <boost/type_traits/is_signed.hpp>
24
#include <boost/mpl/if.hpp>
25
#include <boost/math/common_factor_rt.hpp>
26
#include <boost/chrono/detail/scan_keyword.hpp>
27
#include <boost/utility/enable_if.hpp>
28
#include <boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp>
36
template <class CharT>
38
: public std::locale::facet
41
typedef std::basic_string<CharT> string_type;
42
enum {use_long, use_short};
46
string_type long_seconds_;
47
string_type long_minutes_;
48
string_type long_hours_;
49
string_type short_seconds_;
50
string_type short_minutes_;
51
string_type short_hours_;
53
template <class Period>
54
string_type short_name(Period) const
55
{return ::boost::ratio_string<Period, CharT>::short_name() + short_seconds_;}
57
string_type short_name(ratio<1>) const {return short_seconds_;}
58
string_type short_name(ratio<60>) const {return short_minutes_;}
59
string_type short_name(ratio<3600>) const {return short_hours_;}
61
template <class Period>
62
string_type long_name(Period) const
63
{return ::boost::ratio_string<Period, CharT>::long_name() + long_seconds_;}
65
string_type long_name(ratio<1>) const {return long_seconds_;}
66
string_type long_name(ratio<60>) const {return long_minutes_;}
67
string_type long_name(ratio<3600>) const {return long_hours_;}
71
static std::locale::id id;
73
explicit duration_punct(int use = use_long)
74
: use_short_(use==use_short) {init_C();}
76
duration_punct(int use,
77
const string_type& long_seconds, const string_type& long_minutes,
78
const string_type& long_hours, const string_type& short_seconds,
79
const string_type& short_minutes, const string_type& short_hours);
81
duration_punct(int use, const duration_punct& d);
83
template <class Period>
84
string_type short_name() const
85
{return short_name(typename Period::type());}
87
template <class Period>
88
string_type long_name() const
89
{return long_name(typename Period::type());}
91
template <class Period>
92
string_type plural() const
93
{return long_name(typename Period::type());}
95
template <class Period>
96
string_type singular() const
98
return string_type(long_name(typename Period::type()), 0, long_name(typename Period::type()).size()-1);
101
template <class Period>
102
string_type name() const
104
if (use_short_) return short_name<Period>();
106
return long_name<Period>();
109
template <class Period, class D>
110
string_type name(D v) const
112
if (use_short_) return short_name<Period>();
116
return singular<Period>();
118
return plural<Period>();
122
bool is_short_name() const {return use_short_;}
123
bool is_long_name() const {return !use_short_;}
126
template <class CharT>
128
duration_punct<CharT>::id;
130
template <class CharT>
132
duration_punct<CharT>::init_C()
134
short_seconds_ = CharT('s');
135
short_minutes_ = CharT('m');
136
short_hours_ = CharT('h');
137
const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'};
138
const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'};
139
const CharT h[] = {'h', 'o', 'u', 'r', 's'};
140
long_seconds_.assign(s, s + sizeof(s)/sizeof(s[0]));
141
long_minutes_.assign(m, m + sizeof(m)/sizeof(m[0]));
142
long_hours_.assign(h, h + sizeof(h)/sizeof(h[0]));
145
template <class CharT>
146
duration_punct<CharT>::duration_punct(int use,
147
const string_type& long_seconds, const string_type& long_minutes,
148
const string_type& long_hours, const string_type& short_seconds,
149
const string_type& short_minutes, const string_type& short_hours)
150
: use_short_(use==use_short),
151
long_seconds_(long_seconds),
152
long_minutes_(long_minutes),
153
long_hours_(long_hours),
154
short_seconds_(short_seconds),
155
short_minutes_(short_minutes),
156
short_hours_(short_hours)
159
template <class CharT>
160
duration_punct<CharT>::duration_punct(int use, const duration_punct& d)
161
: use_short_(use==use_short),
162
long_seconds_(d.long_seconds_),
163
long_minutes_(d.long_minutes_),
164
long_hours_(d.long_hours_),
165
short_seconds_(d.short_seconds_),
166
short_minutes_(d.short_minutes_),
167
short_hours_(d.short_hours_)
170
template <class CharT, class Traits>
171
std::basic_ostream<CharT, Traits>&
172
duration_short(std::basic_ostream<CharT, Traits>& os)
174
typedef duration_punct<CharT> Facet;
175
std::locale loc = os.getloc();
176
if (std::has_facet<Facet>(loc))
178
const Facet& f = std::use_facet<Facet>(loc);
179
if (f.is_long_name())
180
os.imbue(std::locale(loc, new Facet(Facet::use_short, f)));
183
os.imbue(std::locale(loc, new Facet(Facet::use_short)));
187
template <class CharT, class Traits>
188
std::basic_ostream<CharT, Traits>&
189
duration_long(std::basic_ostream<CharT, Traits>& os)
191
typedef duration_punct<CharT> Facet;
192
std::locale loc = os.getloc();
193
if (std::has_facet<Facet>(loc))
195
const Facet& f = std::use_facet<Facet>(loc);
196
if (f.is_short_name())
197
os.imbue(std::locale(loc, new Facet(Facet::use_long, f)));
202
template <class CharT, class Traits, class Rep, class Period>
203
std::basic_ostream<CharT, Traits>&
204
operator<<(std::basic_ostream<CharT, Traits>& os, const duration<Rep, Period>& d)
206
typedef duration_punct<CharT> Facet;
207
std::locale loc = os.getloc();
208
if (!std::has_facet<Facet>(loc))
209
os.imbue(std::locale(loc, new Facet));
210
const Facet& f = std::use_facet<Facet>(os.getloc());
211
return os << d.count() << ' ' << f.template name<Period>(d.count());
214
namespace chrono_detail {
215
template <class Rep, bool = is_scalar<Rep>::value>
216
struct duration_io_intermediate
222
struct duration_io_intermediate<Rep, true>
224
typedef typename mpl::if_c
226
is_floating_point<Rep>::value,
230
is_signed<Rep>::value,
237
template <typename intermediate_type>
238
typename enable_if<is_integral<intermediate_type>, bool>::type
239
reduce(intermediate_type& r, unsigned long long& den, std::ios_base::iostate& err)
241
typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
243
// Reduce r * num / den
244
common_type_t t = math::gcd<common_type_t>(common_type_t(r), common_type_t(den));
249
// Conversion to Period is integral and not exact
250
err |= std::ios_base::failbit;
255
template <typename intermediate_type>
256
typename disable_if<is_integral<intermediate_type>, bool>::type
257
reduce(intermediate_type& , unsigned long long& , std::ios_base::iostate& )
264
template <class CharT, class Traits, class Rep, class Period>
265
std::basic_istream<CharT, Traits>&
266
operator>>(std::basic_istream<CharT, Traits>& is, duration<Rep, Period>& d)
268
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
269
typedef duration_punct<CharT> Facet;
270
std::locale loc = is.getloc();
271
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
272
if (!std::has_facet<Facet>(loc)) {
273
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
274
is.imbue(std::locale(loc, new Facet));
276
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
278
const Facet& f = std::use_facet<Facet>(loc);
279
typedef typename chrono_detail::duration_io_intermediate<Rep>::type intermediate_type;
281
std::ios_base::iostate err = std::ios_base::goodbit;
283
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
285
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
288
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
289
// now determine unit
290
typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
293
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
294
if (i != e && *i == ' ') // mandatory ' ' after value
296
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
300
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
301
// unit is num / den (yet to be determined)
302
unsigned long long num = 0;
303
unsigned long long den = 0;
306
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
307
// parse [N/D]s or [N/D]seconds format
310
is >> num >> x >> den;
311
if (!is.good() || (x != '/'))
313
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
314
is.setstate(is.failbit);
320
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
321
is.setstate(is.failbit);
325
const std::basic_string<CharT> units[] =
327
f.template singular<ratio<1> >(),
328
f.template plural<ratio<1> >(),
329
f.template short_name<ratio<1> >()
331
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
332
const std::basic_string<CharT>* k = chrono_detail::scan_keyword(i, e,
333
units, units + sizeof(units)/sizeof(units[0]),
334
//~ std::use_facet<std::ctype<CharT> >(loc),
336
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
338
switch ((k - units) / 3)
341
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
345
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
351
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
352
// parse SI name, short or long
353
const std::basic_string<CharT> units[] =
355
f.template singular<atto>(),
356
f.template plural<atto>(),
357
f.template short_name<atto>(),
358
f.template singular<femto>(),
359
f.template plural<femto>(),
360
f.template short_name<femto>(),
361
f.template singular<pico>(),
362
f.template plural<pico>(),
363
f.template short_name<pico>(),
364
f.template singular<nano>(),
365
f.template plural<nano>(),
366
f.template short_name<nano>(),
367
f.template singular<micro>(),
368
f.template plural<micro>(),
369
f.template short_name<micro>(),
370
f.template singular<milli>(),
371
f.template plural<milli>(),
372
f.template short_name<milli>(),
373
f.template singular<centi>(),
374
f.template plural<centi>(),
375
f.template short_name<centi>(),
376
f.template singular<deci>(),
377
f.template plural<deci>(),
378
f.template short_name<deci>(),
379
f.template singular<deca>(),
380
f.template plural<deca>(),
381
f.template short_name<deca>(),
382
f.template singular<hecto>(),
383
f.template plural<hecto>(),
384
f.template short_name<hecto>(),
385
f.template singular<kilo>(),
386
f.template plural<kilo>(),
387
f.template short_name<kilo>(),
388
f.template singular<mega>(),
389
f.template plural<mega>(),
390
f.template short_name<mega>(),
391
f.template singular<giga>(),
392
f.template plural<giga>(),
393
f.template short_name<giga>(),
394
f.template singular<tera>(),
395
f.template plural<tera>(),
396
f.template short_name<tera>(),
397
f.template singular<peta>(),
398
f.template plural<peta>(),
399
f.template short_name<peta>(),
400
f.template singular<exa>(),
401
f.template plural<exa>(),
402
f.template short_name<exa>(),
403
f.template singular<ratio<1> >(),
404
f.template plural<ratio<1> >(),
405
f.template short_name<ratio<1> >(),
406
f.template singular<ratio<60> >(),
407
f.template plural<ratio<60> >(),
408
f.template short_name<ratio<60> >(),
409
f.template singular<ratio<3600> >(),
410
f.template plural<ratio<3600> >(),
411
f.template short_name<ratio<3600> >()
413
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
414
const std::basic_string<CharT>* k = chrono_detail::scan_keyword(i, e,
415
units, units + sizeof(units)/sizeof(units[0]),
416
//~ std::use_facet<std::ctype<CharT> >(loc),
418
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
419
switch ((k - units) / 3)
423
den = 1000000000000000000ULL;
427
den = 1000000000000000ULL;
431
den = 1000000000000ULL;
474
num = 1000000000000ULL;
478
num = 1000000000000000ULL;
482
num = 1000000000000000000ULL;
498
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
499
is.setstate(err|is.failbit);
503
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
505
// r should be multiplied by (num/den) / Period
506
// Reduce (num/den) / Period to lowest terms
507
unsigned long long gcd_n1_n2 = math::gcd<unsigned long long>(num, Period::num);
508
unsigned long long gcd_d1_d2 = math::gcd<unsigned long long>(den, Period::den);
511
unsigned long long n2 = Period::num / gcd_n1_n2;
512
unsigned long long d2 = Period::den / gcd_d1_d2;
513
if (num > (std::numeric_limits<unsigned long long>::max)() / d2 ||
514
den > (std::numeric_limits<unsigned long long>::max)() / n2)
516
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
517
// (num/den) / Period overflows
518
is.setstate(err|is.failbit);
524
typedef typename common_type<intermediate_type, unsigned long long>::type common_type_t;
526
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
527
// num / den is now factor to multiply by r
528
if (!chrono_detail::reduce(r, den, err))
530
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
531
is.setstate(err|is.failbit);
535
//if (r > ((duration_values<common_type_t>::max)() / num))
536
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
537
if (chrono::detail::gt(r,((duration_values<common_type_t>::max)() / num)))
539
// Conversion to Period overflowed
540
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
541
is.setstate(err|is.failbit);
544
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
545
common_type_t t = r * num;
547
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
551
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
553
if ( (duration_values<Rep>::max)() < pt)
555
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
556
// Conversion to Period overflowed
557
is.setstate(err|is.failbit);
561
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
562
// Success! Store it.
564
d = duration<Rep, Period>(r);
566
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
570
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
571
is.setstate(is.failbit | is.eofbit);
577
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
579
is.setstate(is.failbit|is.eofbit);
581
is.setstate(is.failbit);
582
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
587
//std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl;
588
//is.setstate(is.failbit);
594
template <class CharT, class Traits, class Clock, class Duration>
595
std::basic_ostream<CharT, Traits>&
596
operator<<(std::basic_ostream<CharT, Traits>& os,
597
const time_point<Clock, Duration>& tp)
599
return os << tp.time_since_epoch() << clock_string<Clock, CharT>::since();
602
template <class CharT, class Traits, class Clock, class Duration>
603
std::basic_istream<CharT, Traits>&
604
operator>>(std::basic_istream<CharT, Traits>& is,
605
time_point<Clock, Duration>& tp)
611
const std::basic_string<CharT> units=clock_string<Clock, CharT>::since();
612
std::ios_base::iostate err = std::ios_base::goodbit;
613
typedef std::istreambuf_iterator<CharT, Traits> in_iterator;
616
std::ptrdiff_t k = chrono_detail::scan_keyword(i, e,
618
//~ std::use_facet<std::ctype<CharT> >(is.getloc()),
623
is.setstate(err | is.failbit);
624
// failed to read epoch string
627
tp = time_point<Clock, Duration>(d);
630
is.setstate(is.failbit);
637
#endif // BOOST_CHRONO_CHRONO_IO_HPP