forked from HowardHinnant/date
Move chrono_io.h functionality into date.h.
This commit is contained in:
302
chrono_io.html
302
chrono_io.html
@@ -26,311 +26,15 @@
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="mailto:howard.hinnant@gmail.com">Howard E. Hinnant</a><br/>
|
||||
2016-07-30<br/>
|
||||
2017-04-13<br/>
|
||||
</address>
|
||||
<hr/>
|
||||
<h1 align=center><code>chrono_io</code></h1>
|
||||
|
||||
<h2>Contents</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/HowardHinnant/date">github link</a></li>
|
||||
<li><a href="#Introduction">Introduction</a></li>
|
||||
<li><a href="#Examples">Examples</a></li>
|
||||
<li><a href="#Implementation">Implementation Details</a></li>
|
||||
<li><a href="#Reference">Reference</a></li>
|
||||
</ul>
|
||||
|
||||
<a name="Introduction"></a><h2>Introduction</h2>
|
||||
|
||||
<p>
|
||||
This is a small library which does nothing but add non-configurable, non-localizable
|
||||
streaming to <code>std::chrono::duration</code>. The streaming operator lives in
|
||||
<code>namespace date</code> for convenience purposes, and does not live in
|
||||
<code>namespace std::chrono</code> as that would violate the standard.
|
||||
This library has been moved to
|
||||
<a href="date.html#duration_io"><code>"date.h"</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The entire API of this library is:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
namespace date
|
||||
{
|
||||
|
||||
template <class CharT, class Traits, class Rep, class Period>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||
const std::chrono::duration<Rep, Period>& d);
|
||||
|
||||
} // namespace date
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Just one signature for an entire library? Are you serious?!
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
Very serious.
|
||||
</p>
|
||||
<p>
|
||||
Parsing is not included because there are a million ways to parse durations, and none
|
||||
of them are universally agreed upon. And they are all easily implementable without
|
||||
private access to <code>std::chrono::duration</code> just by parsing arithmetic types
|
||||
and strings.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
No formatting options?!
|
||||
</p>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
No.
|
||||
</p>
|
||||
<p>
|
||||
The formatting provided here is based on an international SI standard. There is
|
||||
no need for localization. If you need other formatting options for streaming
|
||||
your durations that is easy enough for you to supply. What is needed here is
|
||||
zero-effort streaming of <code>chrono::duration</code>s without hassle.
|
||||
Streaming <code>chrono::duration</code>s is the biggest use of
|
||||
<code>.count()</code> (a dangerous type cast), and that use should be handled by
|
||||
a library such as this.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<a name="Examples"></a><h2>Examples</h2>
|
||||
|
||||
<blockquote><pre>
|
||||
#include "chrono_io.h"
|
||||
#include <iostream>
|
||||
|
||||
void f();
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace date;
|
||||
using namespace std::chrono;
|
||||
auto t0 = steady_clock::now();
|
||||
f();
|
||||
auto t1 = steady_clock::now();
|
||||
std::cout << t1 - t0 << '\n';
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
With this library, you don't have to specify the duration type (and cast to it) in timing
|
||||
situations like this. This will create whatever duration is native to
|
||||
<code>steady_clock</code> and print out the value <i>and</i> units for that duration,
|
||||
for example:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
682580ns
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Change <code>steady_clock</code> to <code>system_clock</code> (and if that clock has
|
||||
different units on your platform), and the output automatically changes units for you:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
auto t0 = system_clock::now();
|
||||
f();
|
||||
auto t1 = system_clock::now();
|
||||
std::cout << t1 - t0 << '\n';
|
||||
</pre></blockquote>
|
||||
|
||||
<blockquote><pre>
|
||||
682µs
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
And yes, it really does print out the Greek letter <code>µ</code> and not
|
||||
<code>u</code>. When streaming to <code>char</code>-based streams it uses UTF-8 encoding
|
||||
to represent the Unicode character 'MICRO SIGN' (U+00B5). Otherwise it uses UTF-16 or
|
||||
UTF-32 based on the size of character the stream is using.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In general, if the duration tick period is the same type as one of the non-optional
|
||||
<code>std::ratio</code> SI convenience typedefs (<code>atto</code> thru <code>exa</code>),
|
||||
then the unit will use the internationally accepted symbol for the
|
||||
<a href="https://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> followed
|
||||
by <code>'s'</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition, if the duration tick period is <code>ratio<60></code>, then the
|
||||
printed unit is <code>min</code>. And if the duration tick period is
|
||||
<code>ratio<3600></code>, then the unit is <code>h</code>.
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
std::cout << 1s << '\n';
|
||||
std::cout << 2min << '\n';
|
||||
std::cout << 3h << '\n';
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Outputs:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
1s
|
||||
2min
|
||||
3h
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Sometimes odd durations pop up which have no widely recognized names. For example
|
||||
consider this code:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
using frames = duration<int, ratio<1, 60>>;
|
||||
std::cout << 45ms + frames{5} << '\n';
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
This sum can't be exactly represented as either milliseconds or frames (1/60 of a second).
|
||||
The compiler figures out the coarsest unit which can exactly represent the sum of
|
||||
any millisecond and any frame and auto-generates that unit to hold the sum. For this
|
||||
example that duration will have a tick period of 1/3000 of a second. This library
|
||||
puts that ratio inside of square brackets, and then appends <code>'s'</code>:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
385[1/3000]s
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
If the durations tick period is a whole number of seconds (<code>period::den == 1</code>),
|
||||
then the <code>/1</code> is dropped inside of the square brackets. The following example
|
||||
uses <code>months</code> from <a href="https://github.com/HowardHinnant/date">date.h</a>.
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
std::cout << months{6} << '\n';
|
||||
</pre></blockquote>
|
||||
|
||||
<blockquote><pre>
|
||||
6[2629746]s
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
<i>Trivia:</i> 2,629,746s is the exact length of the average Gregorian month, which is also exactly
|
||||
30.436875 24h days.
|
||||
</p>
|
||||
|
||||
<a name="Implementation"></a><h2>Implementation Details</h2>
|
||||
|
||||
<p>
|
||||
<i>Question:</i> Why are there separate implementations for C++11 and C++14?
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>Answer:</i> The units of a <code>duration</code> are <i>always</i> known at compile
|
||||
time. Thus the string representation of the units is always known at compile time. This
|
||||
is true even when the unit is of the form <code>[num/den]s</code>. But only C++14 has
|
||||
the gravitas to do the complete string conversion at compile time. And now that I've
|
||||
claimed that, I'm sure someone will come up with a C++11 that VS-2015 won't compile anyway.
|
||||
So I need a run-time solution (based on <code>std::basic_string<CharT></code>,
|
||||
and a compile-time solution that currently only gcc and clang with <code>-std=c++14</code>
|
||||
can handle.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For example if you compile the following code with <code>-std=c++14</code> and clang:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
using frames = std::chrono::duration<int, std::ratio<1, 60>>;
|
||||
|
||||
void
|
||||
test(std::ostream& os, std::chrono::milliseconds x, frames y)
|
||||
{
|
||||
using namespace date;
|
||||
os << x + y;
|
||||
}
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
And then inspect the generated assembly, it contains this:
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
movabsq $6714920027984703835, %rax ## imm = 0x5D303030332F315B
|
||||
</pre></blockquote>
|
||||
|
||||
<p>
|
||||
Which is assembly-speak for "[1/3000]" all boiled down to one x86_64 instruction. The
|
||||
<code>'s'</code> wouldn't quite fit within this one instruction and follows in a later
|
||||
instruction. C++14 can do some <i>amazing</i> things at compile time! For C++11 I just
|
||||
gave up and called <code>std::to_string</code>.
|
||||
</p>
|
||||
|
||||
<a name="Reference"></a><h2>Reference</h2>
|
||||
|
||||
<blockquote><pre>
|
||||
template <class CharT, class Traits, class Rep, class Period>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||
const std::chrono::duration<Rep, Period>& d);
|
||||
</pre>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> Equivalent to:
|
||||
</p>
|
||||
<blockquote><pre>
|
||||
os << d.count() << detail::get_units<CharT>(duration<Rep, typename Period::type>{});
|
||||
</pre>
|
||||
<p>
|
||||
Where <code>detail::get_units<CharT>()</code> returns a null-terminated string of
|
||||
<code>CharT</code> which depends only on <code>Period::type</code> as follows (let
|
||||
<code>period</code> be the type <code>Period::type</code>):
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>If <code>period</code> is type <code>std::atto</code>, <code>as</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::femto</code>, <code>fs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::pico</code>, <code>ps</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::nano</code>, <code>ns</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::micro</code>, <code>µs</code> (U+00B5), else</li>
|
||||
<li>if <code>period</code> is type <code>std::milli</code>, <code>ms</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::centi</code>, <code>cs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::deci</code>, <code>ds</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<1></code>, <code>s</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::deca</code>, <code>das</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::hecto</code>, <code>hs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::kilo</code>, <code>ks</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::mega</code>, <code>Ms</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::giga</code>, <code>Gs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::tera</code>, <code>Ts</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::peta</code>, <code>Ps</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::exa</code>, <code>Es</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<60></code>, <code>min</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<3600></code>, <code>h</code>, else</li>
|
||||
<li>if <code>period::den == 1</code>, <code>[num]s</code>, else</li>
|
||||
<li><code>[num/den]s</code>.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
In the list above the use of <code>num</code> and <code>den</code> refer to the
|
||||
static data members of <code>period</code> which are converted to arrays of
|
||||
<code>CharT</code> using a decimal conversion with no leading zeroes.
|
||||
</p>
|
||||
|
||||
</blockquote>
|
||||
<p>
|
||||
<i>Returns:</i> <code>os</code>.
|
||||
</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
62
date.html
62
date.html
@@ -1485,6 +1485,7 @@ and predictable.
|
||||
<tr><td> </td><td><a href="#weeks"><code>weeks</code></a></td></tr>
|
||||
<tr><td> </td><td><a href="#months"><code>months</code></a></td></tr>
|
||||
<tr><td> </td><td><a href="#years"><code>years</code></a></td></tr>
|
||||
<tr><td> </td><td><a href="#duration_io"><code>Formatting and parsing durations</code></a></td></tr>
|
||||
|
||||
<tr><td> </td><td> </td></tr>
|
||||
<tr><td>time_points</td><td> </td></tr>
|
||||
@@ -1674,7 +1675,7 @@ using months = std::chrono::duration
|
||||
<int, std::ratio_divide<years::period, std::ratio<12>>>;
|
||||
</pre></blockquote>
|
||||
|
||||
<h3>Formatting and parsing durations</h3>
|
||||
<a name="duration_io"></a><h3>Formatting and parsing durations</h3>
|
||||
|
||||
<pre>
|
||||
template <class CharT, class Traits, class Rep, class Period>
|
||||
@@ -1721,6 +1722,65 @@ flags): <code>%H</code>, <code>%I</code>, <code>%M</code>, <code>%p</code>,
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<pre>
|
||||
template <class CharT, class Traits, class Rep, class Period>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os,
|
||||
const std::chrono::duration<Rep, Period>& d);
|
||||
</pre>
|
||||
|
||||
<blockquote>
|
||||
<p>
|
||||
<i>Effects:</i> Equivalent to:
|
||||
</p>
|
||||
<blockquote><pre>
|
||||
os << to_string<CharT, Traits>(d.count()) + detail::get_units<CharT>(duration<Rep, typename Period::type>{});
|
||||
</pre>
|
||||
<p>
|
||||
Where <code>to_string</code> is pseudo code that returns a
|
||||
<code>std::basic_string<CharT, Traits></code> representation of <code>d.count()</code>,
|
||||
and <code>detail::get_units<CharT>()</code> returns a null-terminated string of
|
||||
<code>CharT</code> which depends only on <code>Period::type</code> as follows (let
|
||||
<code>period</code> be the type <code>Period::type</code>):
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>If <code>period</code> is type <code>std::atto</code>, <code>as</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::femto</code>, <code>fs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::pico</code>, <code>ps</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::nano</code>, <code>ns</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::micro</code>, <code>µs</code> (U+00B5), else</li>
|
||||
<li>if <code>period</code> is type <code>std::milli</code>, <code>ms</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::centi</code>, <code>cs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::deci</code>, <code>ds</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<1></code>, <code>s</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::deca</code>, <code>das</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::hecto</code>, <code>hs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::kilo</code>, <code>ks</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::mega</code>, <code>Ms</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::giga</code>, <code>Gs</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::tera</code>, <code>Ts</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::peta</code>, <code>Ps</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::exa</code>, <code>Es</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<60></code>, <code>min</code>, else</li>
|
||||
<li>if <code>period</code> is type <code>std::ratio<3600></code>, <code>h</code>, else</li>
|
||||
<li>if <code>period::den == 1</code>, <code>[num]s</code>, else</li>
|
||||
<li><code>[num/den]s</code>.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
In the list above the use of <code>num</code> and <code>den</code> refer to the
|
||||
static data members of <code>period</code> which are converted to arrays of
|
||||
<code>CharT</code> using a decimal conversion with no leading zeroes.
|
||||
</p>
|
||||
|
||||
</blockquote>
|
||||
<p>
|
||||
<i>Returns:</i> <code>os</code>.
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<a name="sys_time"></a><h3><code>sys_time</code></h3>
|
||||
|
||||
<blockquote>
|
||||
|
Reference in New Issue
Block a user