• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1////
2Copyright 2019 Glen Joseph Fernandes
3(glenjofe@gmail.com)
4
5Distributed under the Boost Software License, Version 1.0.
6(http://www.boost.org/LICENSE_1_0.txt)
7////
8
9# IO State Savers, <boost/io/ios_state.hpp>
10:toc:
11:toc-title:
12:idprefix:
13
14## Description
15
16The header `<boost/io/ios_state.hpp>` covers saving the stream state of objects
17in the {cpp} IOStreams system.
18
19## Rationale
20
21Sometimes a certain value has to change only for a limited scope. Saver classes
22save a copy of the current state of some object (or an aspect of an object),
23and reset the object's state at destruction time, undoing any change the object
24may have gone through.
25
26The saver class strategy is helpful when using I/O stream objects. Manipulator
27objects can change some aspect of a stream during input or output. The state
28changed by the manipulator usually sticks to its new value after the I/O
29transaction. This can be a problem if manipulators are used in a function that
30is not supposed to externally change a stream's state.
31
32```
33#include <ostream>
34#include <ios>
35
36void hex_my_byte(std::ostream& os, char byte)
37{
38    os << std::hex << static_cast<unsigned>(byte);
39}
40```
41
42The `os` stream will retain its new hexadecimal printing mode after the call to
43`hex_my_byte`. The stream's printing mode can be saved and restored with manual
44calls to the stream's state inspecting and mutating member functions. The
45manual method becomes unwieldy if the main functionality is complex and/or
46needs to be exception safe. A saver class can implement the better
47"resource acquisition is initialization" strategy.
48
49See the example below for better code, using saver classes.
50
51## Header Synopsis
52
53```
54namespace boost {
55namespace io {
56
57class ios_flags_saver;
58class ios_precision_saver;
59class ios_width_saver;
60class ios_base_all_saver;
61
62template<class Ch, class Tr = std::char_traits<Ch> >
63class basic_ios_iostate_saver;
64
65template<class Ch, class Tr = std::char_traits<Ch> >
66class basic_ios_exception_saver;
67
68template<class Ch, class Tr = std::char_traits<Ch> >
69class basic_ios_tie_saver;
70
71template<class Ch, class Tr = std::char_traits<Ch> >
72class basic_ios_rdbuf_saver;
73
74template<class Ch, class Tr = std::char_traits<Ch> >
75class basic_ios_fill_saver;
76
77template<class Ch, class Tr = std::char_traits<Ch> >
78class basic_ios_locale_saver;
79
80template<class Ch, class Tr = std::char_traits<Ch> >
81class basic_ios_all_saver;
82
83typedef basic_ios_iostate_saver<char>      ios_iostate_saver;
84typedef basic_ios_iostate_saver<wchar_t>   wios_iostate_saver;
85typedef basic_ios_exception_saver<char>    ios_exception_saver;
86typedef basic_ios_exception_saver<wchar_t> wios_exception_saver;
87typedef basic_ios_tie_saver<char>          ios_tie_saver;
88typedef basic_ios_tie_saver<wchar_t>       wios_tie_saver;
89typedef basic_ios_rdbuf_saver<char>        ios_rdbuf_saver;
90typedef basic_ios_rdbuf_saver<wchar_t>     wios_rdbuf_saver;
91typedef basic_ios_fill_saver<char>         ios_fill_saver;
92typedef basic_ios_fill_saver<wchar_t>      wios_fill_saver;
93typedef basic_ios_locale_saver<char>       ios_locale_saver;
94typedef basic_ios_locale_saver<wchar_t>    wios_locale_saver;
95typedef basic_ios_all_saver<char>          ios_all_saver;
96typedef basic_ios_all_saver<wchar_t>       wios_all_saver;
97
98class ios_iword_saver;
99class ios_pword_saver;
100class ios_all_word_saver;
101
102} // io
103} // boost
104```
105
106## Savers for Basic Standard Attributes
107
108The basic saver classes have this format:
109
110[subs=+quotes]
111```
112class saver {
113public:
114    typedef std::ios_base state_type;
115    typedef `implementation_defined` aspect_type;
116
117    explicit saver(state_type& s);
118    saver(state_type& s, const aspect_type& new_value);
119    ~saver();
120
121    void restore();
122};
123```
124
125The `state_type` is the IOStreams base class `std::ios_base`. The user would
126usually place an actual input, output, or combined stream object for the
127state-type parameter, and not a base class object. The first constructor takes
128a stream object and saves a reference to the stream and the current value of a
129particular stream attribute. The second constructor works like the first, and
130uses its second argument to change the stream's attribute to the new
131`aspect_type` value given. The destructor restores the stream's attribute to
132the saved value. The restoration can be activated early (and often) with the
133`restore` member function.
134
135.Basic IOStreams State Saver Classes
136[%header,cols=5*]
137|===
138|Class |Saved Attribute |Attribute Type |Reading Method |Writing Method
139|`ios_flags_saver`
140|Format control flags
141|`std::ios_base::fmtflags`
142|`flags`
143|`flags`
144|`ios_precision_saver`
145|Number of digits to print after decimal point
146|`std::streamsize`
147|`precision`
148|`precision`
149|`ios_width_saver`
150|Minimum field width for printing objects
151|`std::streamsize`
152|`width`
153|`width`
154|===
155
156## Savers for Advanced Standard Attributes
157
158The saver class templates have this format:
159
160[subs=+quotes]
161```
162template<class Ch, class Tr>
163class saver {
164public:
165    typedef std::basic_ios<Ch, Tr> state_type;
166    typedef `implementation-defined` aspect_type;
167
168    explicit saver(state_type& s);
169    saver(state_type& s, const aspect_type& new_value);
170    ~saver();
171
172    void restore();
173};
174```
175
176The `state_type` is a version of the IOStreams base class template
177`std::basic_ios<Ch, Tr>`, where `Ch` is a character type and `Tr` is a
178character traits class. The user would usually place an actual input,
179output, or combined stream object for the state-type parameter, and not a base
180class object. The first constructor takes a stream object and saves a reference
181to the stream and the current value of a particular stream attribute. The
182second constructor works like the first, and uses its second argument to change
183the stream's attribute to the new `aspect_type` value given. The destructor
184restores the stream's attribute to the saved value. The restoration can be
185activated early (and often) with the `restore` member function.
186
187.Advanced IOStreams State Saver Class Templates
188[%header,cols=5*]
189|===
190|Class |Saved Attribute |Attribute Type |Reading Method |Writing Method
191|`basic_ios_iostate_saver<Ch, Tr>`
192|Failure state of the stream [1], [2]
193|`std::ios_base::iostate`
194|`rdstate`
195|`clear`
196|`basic_ios_exception_saver<Ch, Tr>`
197|Which failure states trigger an exception [1]
198|`std::ios_base::iostate`
199|`exceptions`
200|`exceptions`
201|`basic_ios_tie_saver<Ch, Tr>`
202|Output stream synchronized with the stream
203|`std::basic_ostream<Ch, Tr>*`
204|`tie`
205|`tie`
206|`basic_ios_rdbuf_saver<Ch, Tr>`
207|Stream buffer associated with the stream [2]
208|`std::basic_streambuf<Ch, Tr>*`
209|`rdbuf`
210|`rdbuf`
211|`basic_ios_fill_saver<Ch, Tr>`
212|Character used to pad oversized field widths
213|`Ch`
214|`fill`
215|`fill`
216|`basic_ios_locale_saver<Ch, Tr>`
217|Locale information associated with the stream [3]
218|`std::locale`
219|`getloc` (from `std::ios_base`)
220|`imbue` (from `std::basic_ios<Ch, Tr>`)
221|===
222
223### Notes
224
2251. When the failure state flags and/or the failure state exception watching
226flags are changed, an exception is thrown if a match occurs among the two sets
227of flags. This could mean that the constructor or destructor of these class
228templates may throw.
2292. When the associated stream buffer is changed, the stream's failure state set
230is reset to "good" if the given stream buffer's address is non-NULL, but the
231"bad" failure state is set if that address is NULL. This means that a saved
232failure state of "good" may be restored as "bad" if the stream is stripped of
233an associated stream buffer. Worse, given a NULL stream buffer address, an
234exception is thrown if the "bad" failure state is being watched. This could
235mean that the constructor or destructor of these class templates may throw.
2363. The saver for the locale uses the `std::basic_ios<Ch, Tr>` class to extract
237their information, although it could have used the functionality in
238`std::ios_base`. The problem is that the versions of the needed member
239functions in `ios_base` are not polymorphically related to the ones in
240`basic_ios`. The stream classes that will be used with the saver classes should
241use the versions of the member functions closest to them by inheritance, which
242means the ones in `basic_ios`.
243
244## Savers for User-Defined Attributes
245
246There are three class (templates) for combined attribute savers. The
247`ios_base_all_saver` saver class combines the functionality of all the basic
248attribute saver classes. It has a constructor that takes the stream to have its
249state preserved. The `basic_ios_all_saver` combines the functionality of all
250the advanced attribute saver class templates and the combined basic attribute
251saver class. It has a constructor that takes the stream to have its state
252preserved. The `ios_all_word_saver` saver class combines the saver classes that
253preserve user-defined formatting information. Its constructor takes the stream
254to have its attributes saved and the index of the user-defined attributes. The
255destructor for each class restores the saved state. Restoration can be
256activated early (and often) for a class with the restore member function.
257
258## Example
259
260The code used in the rationale can be improved at two places. The printing
261function could use a saver around the code that changes the formatting state.
262Or the calling function can surround the call with a saver. Or both can be
263done, especially if the user does not know if the printing function uses a
264state saver. If the user wants a series of changes back and forth, without
265surrounding each change within a separate block, the restore member function
266can be called between each trial.
267
268```
269#include <boost/io/ios_state.hpp>
270#include <ios>
271#include <iostream>
272#include <ostream>
273
274void new_hex_my_byte(std::ostream& os, char byte)
275{
276    boost::io::ios_flags_saver ifs(os);
277    os << std::hex << static_cast<unsigned>(byte);
278}
279
280int main()
281{
282    // ...
283    {
284        boost::io::ios_all_saver ias(std::cout);
285        new_hex_my_byte(std::cout, 'A');
286    }
287    // ...
288    {
289        boost::io::ios_all_saver ias(std::cerr);
290        new_hex_my_byte(std::cerr, 'b');
291        ias.restore();
292        new_hex_my_byte(std::cerr, 'C');
293    }
294    // ...
295}
296```
297
298## Credits
299
300### Daryle Walker
301
302Started the library. Contributed the initial versions of the format flags,
303precision, width, and user-defined format flags saver classes. Contributed the
304initial versions of the success state, success state exception flags, output
305stream tie, stream buffer, character fill, and locale saver class templates.
306Contributed the combined attribute classes and class template. Contributed the
307test file `ios_state_test.cpp`.
308
309## History
310
311### 20 Dec 2019
312
313Glen Fernandes made all the saver classes non-copyable.
314
315### 28 Feb 2005
316
317Daryle Walker added the restore member functions, based on suggestions by
318Gennadiy Rozental and Rob Stewart.
319
320### 13 Mar 2002
321
322Daryle Walker implemented the initial version.
323