1 //  (C) Copyright Howard Hinnant
2 //  (C) Copyright 2011 Vicente J. Botet Escriba
3 //  Use, modification and distribution are subject to the Boost Software License,
4 //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt).
6 //
7 
8 /**
9  * Duration formatting facet for output.
10  */
11 #ifndef BOOST_CHRONO_IO_DURATION_PUT_HPP
12 #define BOOST_CHRONO_IO_DURATION_PUT_HPP
13 
14 #include <boost/chrono/config.hpp>
15 #include <boost/chrono/io/duration_units.hpp>
16 #include <boost/chrono/process_cpu_clocks.hpp>
17 #include <boost/assert.hpp>
18 #include <locale>
19 
20 namespace boost
21 {
22   namespace chrono
23   {
24 
25     namespace detail
26     {
27       template <class T>
28       struct propagate {
29         typedef T type;
30       };
31       template <>
32       struct propagate<boost::int_least32_t> {
33         typedef boost::int_least64_t type;
34       };
35     }
36     /**
37      * @tparam ChatT a character type
38      * @tparam OutputIterator a model of @c OutputIterator
39      *
40      * The @c duration_put facet provides facilities for formatted output of duration values.
41      * The member function of @c duration_put take a duration and format it into character string representation.
42      *
43      */
44     template <class CharT, class OutputIterator = std::ostreambuf_iterator<CharT> >
45     class duration_put: public std::locale::facet
46     {
47     public:
48       /**
49        * Type of character the facet is instantiated on.
50        */
51       typedef CharT char_type;
52       /**
53        * Type of character string passed to member functions.
54        */
55       typedef std::basic_string<CharT> string_type;
56       /**
57        * Type of iterator used to write in the character buffer.
58        */
59       typedef OutputIterator iter_type;
60 
61       /**
62        * Construct a duration_put facet.
63        * @param refs
64        * @Effects Construct a duration_put facet.
65        * If the @c refs argument is @c 0 then destruction of the object is
66        * delegated to the @c locale, or locales, containing it. This allows
67        * the user to ignore lifetime management issues. On the other had,
68        * if @c refs is @c 1 then the object must be explicitly deleted;
69        * the @c locale will not do so. In this case, the object can be
70        * maintained across the lifetime of multiple locales.
71        */
duration_put(size_t refs=0)72       explicit duration_put(size_t refs = 0) :
73         std::locale::facet(refs)
74       {
75       }
76 
77       /**
78        *
79        * @param s an output stream iterator
80        * @param ios a reference to a ios_base
81        * @param fill the character used as filler
82        * @param d the duration
83        * @param pattern begin of the formatting pattern
84        * @param pat_end end of the formatting pattern
85        *
86        * @Effects Steps through the sequence from @c pattern to @c pat_end,
87        * identifying characters that are part of a pattern sequence. Each character
88        * that is not part of a pattern sequence is written to @c s immediately, and
89        * each pattern sequence, as it is identified, results in a call to
90        * @c put_value or @c put_unit;
91        * thus, pattern elements and other characters are interleaved in the output
92        * in the order in which they appear in the pattern. Pattern sequences are
93        * identified by converting each character @c c to a @c char value as if by
94        * @c ct.narrow(c,0), where @c ct is a reference to @c ctype<charT> obtained from
95        * @c ios.getloc(). The first character of each sequence is equal to @c '%',
96        * followed by a pattern specifier character @c spec, which can be @c 'v' for
97        * the duration value or @c 'u' for the duration unit. .
98        * For each valid pattern sequence identified, calls
99        * <c>put_value(s, ios, fill, d)</c> or <c>put_unit(s, ios, fill, d)</c>.
100        *
101        * @Returns An iterator pointing immediately after the last character produced.
102        */
103       template <typename Rep, typename Period>
put(iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d,const CharT * pattern,const CharT * pat_end,const char_type * val=0) const104       iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration<Rep, Period> const& d, const CharT* pattern,
105           const CharT* pat_end, const char_type* val = 0) const
106       {
107         if (std::has_facet<duration_units<CharT> >(ios.getloc()))
108         {
109           duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(
110               ios.getloc());
111           return put(facet, s, ios, fill, d, pattern, pat_end, val);
112         }
113         else
114         {
115           duration_units_default<CharT> facet;
116           return put(facet, s, ios, fill, d, pattern, pat_end, val);
117         }
118       }
119 
120       template <typename Rep, typename Period>
put(duration_units<CharT> const & units_facet,iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d,const CharT * pattern,const CharT * pat_end,const char_type * val=0) const121       iter_type put(duration_units<CharT> const& units_facet, iter_type s, std::ios_base& ios, char_type fill,
122           duration<Rep, Period> const& d, const CharT* pattern, const CharT* pat_end, const char_type* val = 0) const
123       {
124 
125         const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc());
126         for (; pattern != pat_end; ++pattern)
127         {
128           if (ct.narrow(*pattern, 0) == '%')
129           {
130             if (++pattern == pat_end)
131             {
132               *s++ = pattern[-1];
133               break;
134             }
135             char fmt = ct.narrow(*pattern, 0);
136             switch (fmt)
137             {
138             case 'v':
139             {
140               s = put_value(s, ios, fill, d, val);
141               break;
142             }
143             case 'u':
144             {
145               s = put_unit(units_facet, s, ios, fill, d);
146               break;
147             }
148             default:
149               BOOST_ASSERT(false && "Boost::Chrono internal error.");
150               break;
151             }
152           }
153           else
154             *s++ = *pattern;
155         }
156         return s;
157       }
158 
159       /**
160        *
161        * @param s an output stream iterator
162        * @param ios a reference to a ios_base
163        * @param fill the character used as filler
164        * @param d the duration
165        * @Effects imbue in @c ios the @c duration_units_default facet if not already present.
166        * Retrieves Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if
167        * @code
168        *   return put(s, ios, d, str.data(), str.data() + str.size());
169        * @endcode
170        * @Returns An iterator pointing immediately after the last character produced.
171        */
172       template <typename Rep, typename Period>
put(iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d,const char_type * val=0) const173       iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration<Rep, Period> const& d, const char_type* val = 0) const
174       {
175         if (std::has_facet<duration_units<CharT> >(ios.getloc()))
176         {
177           duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(
178               ios.getloc());
179           std::basic_string<CharT> str = facet.get_pattern();
180           return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val);
181         }
182         else
183         {
184           duration_units_default<CharT> facet;
185           std::basic_string<CharT> str = facet.get_pattern();
186 
187           return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val);
188         }
189       }
190 
191       /**
192        *
193        * @param s an output stream iterator
194        * @param ios a reference to a ios_base
195        * @param fill the character used as filler
196        * @param d the duration
197        * @Effects As if s=std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill, static_cast<long int> (d.count())).
198        * @Returns s, iterator pointing immediately after the last character produced.
199        */
200       template <typename Rep, typename Period>
put_value(iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d,const char_type * val=0) const201       iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration<Rep, Period> const& d, const char_type* val = 0) const
202       {
203         if (val)
204         {
205           while (*val) {
206             *s = *val;
207             s++; val++;
208           }
209           return s;
210         }
211         return std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill,
212             static_cast<typename detail::propagate<Rep>::type> (d.count()));
213       }
214 
215       template <typename Rep, typename Period>
put_value(iter_type s,std::ios_base & ios,char_type fill,duration<process_times<Rep>,Period> const & d,const char_type * =0) const216       iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration<process_times<Rep>, Period> const& d, const char_type* = 0) const
217       {
218         *s++ = CharT('{');
219         s = put_value(s, ios, fill, process_real_cpu_clock::duration(d.count().real));
220         *s++ = CharT(';');
221         s = put_value(s, ios, fill, process_user_cpu_clock::duration(d.count().user));
222         *s++ = CharT(';');
223         s = put_value(s, ios, fill, process_system_cpu_clock::duration(d.count().system));
224         *s++ = CharT('}');
225         return s;
226       }
227 
228       /**
229        *
230        * @param s an output stream iterator
231        * @param ios a reference to a ios_base
232        * @param fill the character used as filler
233        * @param d the duration
234        * @Effects Let facet be the duration_units<CharT> facet associated to ios. If the associated unit is named,
235        * as if
236        * @code
237           string_type str = facet.get_unit(get_duration_style(ios), d);
238           s=std::copy(str.begin(), str.end(), s);
239        * @endcode
240        * Otherwise, format the unit as "[Period::num/Period::den]" followed by the unit associated to [N/D] obtained using facet.get_n_d_unit(get_duration_style(ios), d)
241        * @Returns s, iterator pointing immediately after the last character produced.
242        */
243       template <typename Rep, typename Period>
put_unit(iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d) const244       iter_type put_unit(iter_type s, std::ios_base& ios, char_type fill, duration<Rep, Period> const& d) const
245       {
246         if (std::has_facet<duration_units<CharT> >(ios.getloc()))
247         {
248           duration_units<CharT> const&facet = std::use_facet<duration_units<CharT> >(
249               ios.getloc());
250           return put_unit(facet, s, ios, fill, d);
251         }
252         else
253         {
254           duration_units_default<CharT> facet;
255           return put_unit(facet, s, ios, fill, d);
256         }
257       }
258 
259       template <typename Rep, typename Period>
put_unit(duration_units<CharT> const & facet,iter_type s,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d) const260       iter_type put_unit(duration_units<CharT> const& facet, iter_type s, std::ios_base& ios, char_type fill,
261           duration<Rep, Period> const& d) const
262       {
263         if (facet.template is_named_unit<Period>()) {
264           string_type str = facet.get_unit(get_duration_style(ios), d);
265           s=std::copy(str.begin(), str.end(), s);
266         } else {
267           *s++ = CharT('[');
268           std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill, Period::num);
269           *s++ = CharT('/');
270           std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill, Period::den);
271           *s++ = CharT(']');
272           string_type str = facet.get_n_d_unit(get_duration_style(ios), d);
273           s=std::copy(str.begin(), str.end(), s);
274         }
275         return s;
276       }
277       template <typename Rep, typename Period>
put_unit(duration_units<CharT> const & facet,iter_type s,std::ios_base & ios,char_type fill,duration<process_times<Rep>,Period> const & d) const278       iter_type put_unit(duration_units<CharT> const& facet, iter_type s, std::ios_base& ios, char_type fill,
279           duration<process_times<Rep>, Period> const& d) const
280       {
281         duration<Rep,Period> real(d.count().real);
282         if (facet.template is_named_unit<Period>()) {
283           string_type str = facet.get_unit(get_duration_style(ios), real);
284           s=std::copy(str.begin(), str.end(), s);
285         } else {
286           *s++ = CharT('[');
287           std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill, Period::num);
288           *s++ = CharT('/');
289           std::use_facet<std::num_put<CharT, iter_type> >(ios.getloc()).put(s, ios, fill, Period::den);
290           *s++ = CharT(']');
291           string_type str = facet.get_n_d_unit(get_duration_style(ios), real);
292           s=std::copy(str.begin(), str.end(), s);
293         }
294         return s;
295       }
296 
297       /**
298        * Unique identifier for this type of facet.
299        */
300       static std::locale::id id;
301 
302       /**
303        * @Effects Destroy the facet
304        */
~duration_put()305       ~duration_put()
306       {
307       }
308 
309     };
310 
311     template <class CharT, class OutputIterator>
312     std::locale::id duration_put<CharT, OutputIterator>::id;
313 
314   } // chrono
315 } // boost
316 
317 #endif  // header
318