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 // This code was adapted by Vicente from Howard Hinnant's experimental work
8 // on chrono i/o to Boost
9 
10 #ifndef BOOST_CHRONO_IO_DURATION_IO_HPP
11 #define BOOST_CHRONO_IO_DURATION_IO_HPP
12 
13 #include <boost/chrono/duration.hpp>
14 #include <boost/ratio/ratio_io.hpp>
15 #include <boost/chrono/io/duration_style.hpp>
16 #include <boost/chrono/io/ios_base_state.hpp>
17 #include <boost/chrono/io/duration_put.hpp>
18 #include <boost/chrono/io/duration_get.hpp>
19 #include <boost/chrono/io/utility/manip_base.hpp>
20 #include <boost/detail/no_exceptions_support.hpp>
21 #include <boost/type_traits/is_integral.hpp>
22 #include <boost/type_traits/is_floating_point.hpp>
23 #include <locale>
24 #include <iosfwd>
25 #include <sstream>
26 
27 namespace boost
28 {
29   namespace chrono
30   {
31 
32     /**
33      * duration parameterized manipulator.
34      */
35 
36     class duration_fmt: public manip<duration_fmt>
37     {
38       duration_style style_;
39     public:
40 
41       /**
42        * explicit manipulator constructor from a @c duration_style
43        */
duration_fmt(duration_style style)44       explicit duration_fmt(duration_style style)BOOST_NOEXCEPT
45       : style_(style)
46       {}
47 
48       /**
49        * Change the duration_style ios state;
50        */
operator ()(std::ios_base & ios) const51       void operator()(std::ios_base &ios) const
52 
53       {
54         set_duration_style(ios, style_);
55       }
56     };
57 
58     /**
59      * duration_style i/o saver.
60      *
61      * See Boost.IO i/o state savers for a motivating compression.
62      */
63     struct duration_style_io_saver
64     {
65 
66       //! the type of the state to restore
67       typedef std::ios_base state_type;
68       //! the type of aspect to save
69       typedef duration_style aspect_type;
70 
71       /**
72        * Explicit construction from an i/o stream.
73        *
74        * Store a reference to the i/o stream and the value of the associated @c duration_style.
75        */
duration_style_io_saverboost::chrono::duration_style_io_saver76       explicit duration_style_io_saver(state_type &s) :
77         s_save_(s), a_save_(get_duration_style(s))
78       {
79       }
80 
81       /**
82        * Construction from an i/o stream and a @c duration_style to restore.
83        *
84        * Stores a reference to the i/o stream and the value @c new_value @c duration_style to set.
85        */
duration_style_io_saverboost::chrono::duration_style_io_saver86       duration_style_io_saver(state_type &s, aspect_type new_value) :
87         s_save_(s), a_save_(get_duration_style(s))
88       {
89         set_duration_style(s, new_value);
90       }
91 
92       /**
93        * Destructor.
94        *
95        * Restores the i/o stream with the duration_style to be restored.
96        */
~duration_style_io_saverboost::chrono::duration_style_io_saver97       ~duration_style_io_saver()
98       {
99         this->restore();
100       }
101 
102       /**
103        * Restores the i/o stream with the duration_style to be restored.
104        */
restoreboost::chrono::duration_style_io_saver105       void restore()
106       {
107         set_duration_style(s_save_, a_save_);
108       }
109 
110     private:
111       duration_style_io_saver& operator=(duration_style_io_saver const& rhs) ;
112 
113       state_type& s_save_;
114       aspect_type a_save_;
115     };
116 
117     template <class Rep>
118     struct duration_put_enabled
119       : integral_constant<bool,
120           is_integral<Rep>::value || is_floating_point<Rep>::value
121         >
122      {};
123 
124 
125     /**
126      * duration stream inserter
127      * @param os the output stream
128      * @param d to value to insert
129      * @return @c os
130      */
131 
132     template <class CharT, class Traits, class Rep, class Period>
133     typename boost::enable_if_c< ! duration_put_enabled<Rep>::value, std::basic_ostream<CharT, Traits>& >::type
operator <<(std::basic_ostream<CharT,Traits> & os,const duration<Rep,Period> & d)134     operator<<(std::basic_ostream<CharT, Traits>& os, const duration<Rep, Period>& d)
135     {
136       std::basic_ostringstream<CharT, Traits> ostr;
137       ostr << d.count();
138       duration<int, Period> dd(0);
139       bool failed = false;
140       BOOST_TRY
141       {
142         std::ios_base::iostate err = std::ios_base::goodbit;
143         BOOST_TRY
144         {
145           typename std::basic_ostream<CharT, Traits>::sentry opfx(os);
146           if (bool(opfx))
147           {
148             if (!std::has_facet<duration_put<CharT> >(os.getloc()))
149             {
150               if (duration_put<CharT> ().put(os, os, os.fill(), dd, ostr.str().c_str()) .failed())
151               {
152                 err = std::ios_base::badbit;
153               }
154             }
155             else if (std::use_facet<duration_put<CharT> >(os.getloc()) .put(os, os, os.fill(), dd, ostr.str().c_str()) .failed())
156             {
157               err = std::ios_base::badbit;
158             }
159             os.width(0);
160           }
161         }
162         BOOST_CATCH(...)
163         {
164           bool flag = false;
165           BOOST_TRY
166           {
167             os.setstate(std::ios_base::failbit);
168           }
169           BOOST_CATCH (std::ios_base::failure )
170           {
171             flag = true;
172           }
173           BOOST_CATCH_END
174           if (flag) throw;
175         }
176         BOOST_CATCH_END
177         if (err) os.setstate(err);
178         return os;
179       }
180       BOOST_CATCH(...)
181       {
182         failed = true;
183       }
184       BOOST_CATCH_END
185       if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit);
186       return os;
187 
188     }
189 
190     template <class CharT, class Traits, class Rep, class Period>
191     typename boost::enable_if_c< duration_put_enabled<Rep>::value, std::basic_ostream<CharT, Traits>& >::type
operator <<(std::basic_ostream<CharT,Traits> & os,const duration<Rep,Period> & d)192     operator<<(std::basic_ostream<CharT, Traits>& os, const duration<Rep, Period>& d)
193     {
194       bool failed = false;
195       BOOST_TRY
196       {
197         std::ios_base::iostate err = std::ios_base::goodbit;
198         BOOST_TRY
199         {
200           typename std::basic_ostream<CharT, Traits>::sentry opfx(os);
201           if (bool(opfx))
202           {
203             if (!std::has_facet<duration_put<CharT> >(os.getloc()))
204             {
205               if (duration_put<CharT> ().put(os, os, os.fill(), d) .failed())
206               {
207                 err = std::ios_base::badbit;
208               }
209             }
210             else if (std::use_facet<duration_put<CharT> >(os.getloc()) .put(os, os, os.fill(), d) .failed())
211             {
212               err = std::ios_base::badbit;
213             }
214             os.width(0);
215           }
216         }
217         BOOST_CATCH(...)
218         {
219           bool flag = false;
220           BOOST_TRY
221           {
222             os.setstate(std::ios_base::failbit);
223           }
224           BOOST_CATCH (std::ios_base::failure )
225           {
226             flag = true;
227           }
228           BOOST_CATCH_END
229           if (flag) throw;
230         }
231         BOOST_CATCH_END
232         if (err) os.setstate(err);
233         return os;
234       }
235       BOOST_CATCH(...)
236       {
237         failed = true;
238       }
239       BOOST_CATCH_END
240       if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit);
241       return os;
242     }
243 
244     /**
245      *
246      * @param is the input stream
247      * @param d the duration
248      * @return @c is
249      */
250     template <class CharT, class Traits, class Rep, class Period>
251     std::basic_istream<CharT, Traits>&
operator >>(std::basic_istream<CharT,Traits> & is,duration<Rep,Period> & d)252     operator>>(std::basic_istream<CharT, Traits>& is, duration<Rep, Period>& d)
253     {
254       std::ios_base::iostate err = std::ios_base::goodbit;
255 
256       BOOST_TRY
257       {
258         typename std::basic_istream<CharT, Traits>::sentry ipfx(is);
259         if (bool(ipfx))
260         {
261           if (!std::has_facet<duration_get<CharT> >(is.getloc()))
262           {
263             duration_get<CharT> ().get(is, std::istreambuf_iterator<CharT, Traits>(), is, err, d);
264           }
265           else
266           {
267             std::use_facet<duration_get<CharT> >(is.getloc()) .get(is, std::istreambuf_iterator<CharT, Traits>(), is,
268                 err, d);
269           }
270         }
271       }
272       BOOST_CATCH (...)
273       {
274         bool flag = false;
275         BOOST_TRY
276         {
277           is.setstate(std::ios_base::failbit);
278         }
279         BOOST_CATCH (std::ios_base::failure )
280         {
281           flag = true;
282         }
283         BOOST_CATCH_END
284         if (flag) { BOOST_RETHROW }
285       }
286       BOOST_CATCH_END
287       if (err) is.setstate(err);
288       return is;
289     }
290 
291   } // chrono
292 
293 }
294 
295 #endif  // header
296