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_TIME_POINT_PUT_HPP
12 #define BOOST_CHRONO_IO_TIME_POINT_PUT_HPP
13 
14 #include <boost/chrono/config.hpp>
15 #include <boost/chrono/io/time_point_units.hpp>
16 #include <boost/chrono/io/duration_put.hpp>
17 #include <boost/assert.hpp>
18 #include <locale>
19 
20 namespace boost
21 {
22   namespace chrono
23   {
24 
25     /**
26      * @tparam ChatT a character type
27      * @tparam OutputIterator a model of @c OutputIterator
28      *
29      * The @c time_point_put facet provides facilities for formatted output of @c time_point values.
30      * The member function of @c time_point_put take a @c time_point and format it into character string representation.
31      *
32      */
33     template <class CharT, class OutputIterator = std::ostreambuf_iterator<CharT> >
34     class time_point_put: public std::locale::facet
35     {
36     public:
37       /**
38        * Type of character the facet is instantiated on.
39        */
40       typedef CharT char_type;
41       /**
42        * Type of character string passed to member functions.
43        */
44       typedef std::basic_string<CharT> string_type;
45       /**
46        * Type of iterator used to write in the character buffer.
47        */
48       typedef OutputIterator iter_type;
49 
50       /**
51        * Construct a time_point_put facet.
52        * @param refs
53        * @Effects Construct a time_point_put facet.
54        * If the @c refs argument is @c 0 then destruction of the object is
55        * delegated to the @c locale, or locales, containing it. This allows
56        * the user to ignore lifetime management issues. On the other had,
57        * if @c refs is @c 1 then the object must be explicitly deleted;
58        * the @c locale will not do so. In this case, the object can be
59        * maintained across the lifetime of multiple locales.
60        */
time_point_put(size_t refs=0)61       explicit time_point_put(size_t refs = 0) :
62         std::locale::facet(refs)
63       {
64       }
65 
66       /**
67        * @param i an output stream iterator
68        * @param ios a reference to a ios_base
69        * @param fill the character used as filler
70        * @param tp the @c time_point
71        * @param pattern begin of the formatting pattern
72        * @param pat_end end of the formatting pattern
73        *
74        * @Effects Steps through the sequence from @c pattern to @c pat_end,
75        * identifying characters that are part of a pattern sequence. Each character
76        * that is not part of a pattern sequence is written to @c s immediately, and
77        * each pattern sequence, as it is identified, results in a call to
78        * @c put_duration or @c put_epoch;
79        * thus, pattern elements and other characters are interleaved in the output
80        * in the order in which they appear in the pattern. Pattern sequences are
81        * identified by converting each character @c c to a @c char value as if by
82        * @c ct.narrow(c,0), where @c ct is a reference to @c ctype<charT> obtained from
83        * @c ios.getloc(). The first character of each sequence is equal to @c '%',
84        * followed by a pattern specifier character @c spec, which can be @c 'd' for
85        * the duration value or @c 'e' for the epoch.
86        * For each valid pattern sequence identified, calls
87        * <c>put_duration(s, ios, fill, tp.time_since_epoch())</c> or <c>put_epoch(s, ios)</c>.
88        *
89        * @Returns An iterator pointing immediately after the last character produced.
90        */
91 
92       template <class Clock, class Duration>
put(iter_type i,std::ios_base & ios,char_type fill,time_point<Clock,Duration> const & tp,const CharT * pattern,const CharT * pat_end) const93       iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point<Clock, Duration> const& tp, const CharT* pattern,
94           const CharT* pat_end) const
95       {
96         if (std::has_facet<time_point_units<CharT> >(ios.getloc()))
97         {
98           time_point_units<CharT> const &facet =
99               std::use_facet<time_point_units<CharT> >(ios.getloc());
100           return put(facet, i, ios, fill, tp, pattern, pat_end);
101         }
102         else
103         {
104           time_point_units_default<CharT> facet;
105           return put(facet, i, ios, fill, tp, pattern, pat_end);
106         }
107       }
108 
109       template <class Clock, class Duration>
put(time_point_units<CharT> const & units_facet,iter_type s,std::ios_base & ios,char_type fill,time_point<Clock,Duration> const & tp,const CharT * pattern,const CharT * pat_end) const110       iter_type put(time_point_units<CharT> const& units_facet, iter_type s, std::ios_base& ios, char_type fill,
111           time_point<Clock, Duration> const& tp, const CharT* pattern, const CharT* pat_end) const
112       {
113 
114         const std::ctype<char_type>& ct = std::use_facet<std::ctype<char_type> >(ios.getloc());
115         for (; pattern != pat_end; ++pattern)
116         {
117           if (ct.narrow(*pattern, 0) == '%')
118           {
119             if (++pattern == pat_end)
120             {
121               *s++ = pattern[-1];
122               break;
123             }
124             char fmt = ct.narrow(*pattern, 0);
125             switch (fmt)
126             {
127             case 'd':
128             {
129               s = put_duration(s, ios, fill, tp.time_since_epoch());
130               break;
131             }
132             case 'e':
133             {
134               s = put_epoch<Clock> (units_facet, s, ios);
135               break;
136             }
137             default:
138               BOOST_ASSERT(false && "Boost::Chrono internal error.");
139               break;
140             }
141           }
142           else
143             *s++ = *pattern;
144         }
145         return s;
146       }
147 
148       /**
149        * @param i an output stream iterator
150        * @param ios a reference to a ios_base
151        * @param fill the character used as filler
152        * @param tp the @c time_point
153        * @param pattern begin of the formatting pattern
154        * @param pat_end end of the formatting pattern
155        *
156        * @Effects Stores the time_point pattern from the @c time_point_unit facet in let say @c str. Last as if
157        * @code
158        *   return put(s, ios, dill, tp, str.data(), str.data() + str.size());
159        * @endcode
160        * @Returns An iterator pointing immediately after the last character produced.
161        */
162       template <class Clock, class Duration>
put(iter_type i,std::ios_base & ios,char_type fill,time_point<Clock,Duration> const & tp) const163       iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point<Clock, Duration> const& tp) const
164       {
165         if (std::has_facet<time_point_units<CharT> >(ios.getloc()))
166         {
167           time_point_units<CharT> const &facet =
168               std::use_facet<time_point_units<CharT> >(ios.getloc());
169           std::basic_string<CharT> str = facet.get_pattern();
170           return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size());
171         }
172         else
173         {
174           time_point_units_default<CharT> facet;
175           std::basic_string<CharT> str = facet.get_pattern();
176           return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size());
177         }
178       }
179 
180       /**
181        * @param i an output stream iterator
182        * @param ios a reference to a ios_base
183        * @param fill the character used as filler
184        * @param d the @c duration
185        * @Effects As if <c>facet.put(s, ios, fill, d)</c> where facet is the @c duration_put<CharT> facet associated
186        * to the @c ios or a new instance of @c duration_put<CharT>.
187        * @Returns An iterator pointing immediately after the last character produced.
188        */
189       template <typename Rep, typename Period>
put_duration(iter_type i,std::ios_base & ios,char_type fill,duration<Rep,Period> const & d) const190       iter_type put_duration(iter_type i, std::ios_base& ios, char_type fill, duration<Rep, Period> const& d) const
191       {
192         if (std::has_facet<duration_put<CharT> >(ios.getloc()))
193         {
194           duration_put<CharT> const &facet = std::use_facet<duration_put<CharT> >(ios.getloc());
195           return facet.put(i, ios, fill, d);
196         }
197         else
198         {
199           duration_put<CharT> facet;
200           return facet.put(i, ios, fill, d);
201         }
202       }
203 
204       /**
205        *
206        * @param i an output stream iterator
207        * @param ios a reference to a ios_base
208        * @Effects As if
209        * @code
210        * string_type str = facet.template get_epoch<Clock>();
211        * s=std::copy(str.begin(), str.end(), s);
212        * @endcode
213        * where facet is the @c time_point_units<CharT> facet associated
214        * to the @c ios or a new instance of @c time_point_units_default<CharT>.
215        * @Returns s, iterator pointing immediately after the last character produced.
216        */
217 
218       template <typename Clock>
put_epoch(iter_type i,std::ios_base & os) const219       iter_type put_epoch(iter_type i, std::ios_base& os) const
220       {
221         if (std::has_facet<time_point_units<CharT> >(os.getloc()))
222         {
223           time_point_units<CharT> const &facet = std::use_facet<time_point_units<CharT> >(os.getloc());
224           return put_epoch<Clock> (facet, i, os);
225         }
226         else
227         {
228           time_point_units_default<CharT> facet;
229           return put_epoch<Clock> (facet, i, os);
230         }
231       }
232 
233       template <typename Clock>
put_epoch(time_point_units<CharT> const & facet,iter_type s,std::ios_base &) const234       iter_type put_epoch(time_point_units<CharT> const& facet, iter_type s, std::ios_base&) const
235       {
236         string_type str = facet.template get_epoch<Clock>();
237         s= std::copy(str.begin(), str.end(), s);
238         return s;
239       }
240 
241       /**
242        * Unique identifier for this type of facet.
243        */
244       static std::locale::id id;
245 
246       /**
247        * @Effects Destroy the facet
248        */
~time_point_put()249       ~time_point_put()
250       {
251       }
252 
253     };
254 
255     template <class CharT, class OutputIterator>
256     std::locale::id time_point_put<CharT, OutputIterator>::id;
257 
258   } // chrono
259 } // boost
260 
261 #endif  // header
262