1 | // tuple_io.hpp -------------------------------------------------------------- |
2 | |
3 | // Copyright (C) 2001 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) |
4 | // 2001 Gary Powell (gary.powell@sierra.com) |
5 | // |
6 | // Distributed under the Boost Software License, Version 1.0. (See |
7 | // accompanying file LICENSE_1_0.txt or copy at |
8 | // http://www.boost.org/LICENSE_1_0.txt) |
9 | // For more information, see http://www.boost.org |
10 | |
11 | // ---------------------------------------------------------------------------- |
12 | |
13 | #ifndef BOOST_TUPLE_IO_HPP |
14 | #define BOOST_TUPLE_IO_HPP |
15 | |
16 | #include <istream> |
17 | #include <ostream> |
18 | |
19 | #include <sstream> |
20 | |
21 | #include "boost/tuple/tuple.hpp" |
22 | |
23 | // This is ugly: one should be using twoargument isspace since whitspace can |
24 | // be locale dependent, in theory at least. |
25 | // not all libraries implement have the two-arg version, so we need to |
26 | // use the one-arg one, which one should get with <cctype> but there seem |
27 | // to be exceptions to this. |
28 | |
29 | #if !defined (BOOST_NO_STD_LOCALE) |
30 | |
31 | #include <locale> // for two-arg isspace |
32 | |
33 | #else |
34 | |
35 | #include <cctype> // for one-arg (old) isspace |
36 | #include <ctype.h> // Metrowerks does not find one-arg isspace from cctype |
37 | |
38 | #endif |
39 | |
40 | namespace boost { |
41 | namespace tuples { |
42 | |
43 | namespace detail { |
44 | |
45 | class format_info { |
46 | public: |
47 | |
48 | enum manipulator_type { open, close, delimiter }; |
49 | BOOST_STATIC_CONSTANT(int, number_of_manipulators = delimiter + 1); |
50 | private: |
51 | |
52 | static int get_stream_index (int m) |
53 | { |
54 | static const int stream_index[number_of_manipulators] |
55 | = { std::ios::xalloc(), std::ios::xalloc(), std::ios::xalloc() }; |
56 | |
57 | return stream_index[m]; |
58 | } |
59 | |
60 | format_info(const format_info&); |
61 | format_info(); |
62 | |
63 | |
64 | public: |
65 | |
66 | template<class CharType, class CharTrait> |
67 | static CharType get_manipulator(std::basic_ios<CharType, CharTrait>& i, |
68 | manipulator_type m) { |
69 | // The manipulators are stored as long. |
70 | // A valid instanitation of basic_stream allows CharType to be any POD, |
71 | // hence, the static_cast may fail (it fails if long is not convertible |
72 | // to CharType |
73 | CharType c = static_cast<CharType>(i.iword(get_stream_index(m)) ); |
74 | // parentheses and space are the default manipulators |
75 | if (!c) { |
76 | switch(m) { |
77 | case detail::format_info::open : c = i.widen('('); break; |
78 | case detail::format_info::close : c = i.widen(')'); break; |
79 | case detail::format_info::delimiter : c = i.widen(' '); break; |
80 | } |
81 | } |
82 | return c; |
83 | } |
84 | |
85 | |
86 | template<class CharType, class CharTrait> |
87 | static void set_manipulator(std::basic_ios<CharType, CharTrait>& i, |
88 | manipulator_type m, CharType c) { |
89 | // The manipulators are stored as long. |
90 | // A valid instanitation of basic_stream allows CharType to be any POD, |
91 | // hence, the static_cast may fail (it fails if CharType is not |
92 | // convertible long. |
93 | i.iword(get_stream_index(m)) = static_cast<long>(c); |
94 | } |
95 | }; |
96 | |
97 | } // end of namespace detail |
98 | |
99 | template<class CharType> |
100 | class tuple_manipulator { |
101 | const detail::format_info::manipulator_type mt; |
102 | CharType f_c; |
103 | public: |
104 | explicit tuple_manipulator(detail::format_info::manipulator_type m, |
105 | const char c = 0) |
106 | : mt(m), f_c(c) {} |
107 | |
108 | template<class CharTrait> |
109 | void set(std::basic_ios<CharType, CharTrait> &io) const { |
110 | detail::format_info::set_manipulator(io, mt, f_c); |
111 | } |
112 | }; |
113 | |
114 | |
115 | template<class CharType, class CharTrait> |
116 | inline std::basic_ostream<CharType, CharTrait>& |
117 | operator<<(std::basic_ostream<CharType, CharTrait>& o, const tuple_manipulator<CharType>& m) { |
118 | m.set(o); |
119 | return o; |
120 | } |
121 | |
122 | template<class CharType, class CharTrait> |
123 | inline std::basic_istream<CharType, CharTrait>& |
124 | operator>>(std::basic_istream<CharType, CharTrait>& i, const tuple_manipulator<CharType>& m) { |
125 | m.set(i); |
126 | return i; |
127 | } |
128 | |
129 | |
130 | template<class CharType> |
131 | inline tuple_manipulator<CharType> set_open(const CharType c) { |
132 | return tuple_manipulator<CharType>(detail::format_info::open, c); |
133 | } |
134 | |
135 | template<class CharType> |
136 | inline tuple_manipulator<CharType> set_close(const CharType c) { |
137 | return tuple_manipulator<CharType>(detail::format_info::close, c); |
138 | } |
139 | |
140 | template<class CharType> |
141 | inline tuple_manipulator<CharType> set_delimiter(const CharType c) { |
142 | return tuple_manipulator<CharType>(detail::format_info::delimiter, c); |
143 | } |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | // ------------------------------------------------------------- |
150 | // printing tuples to ostream in format (a b c) |
151 | // parentheses and space are defaults, but can be overriden with manipulators |
152 | // set_open, set_close and set_delimiter |
153 | |
154 | namespace detail { |
155 | |
156 | // Note: The order of the print functions is critical |
157 | // to let a conforming compiler find and select the correct one. |
158 | |
159 | |
160 | template<class CharType, class CharTrait, class T1> |
161 | inline std::basic_ostream<CharType, CharTrait>& |
162 | print(std::basic_ostream<CharType, CharTrait>& o, const cons<T1, null_type>& t) { |
163 | return o << t.head; |
164 | } |
165 | |
166 | |
167 | template<class CharType, class CharTrait> |
168 | inline std::basic_ostream<CharType, CharTrait>& |
169 | print(std::basic_ostream<CharType, CharTrait>& o, const null_type&) { |
170 | return o; |
171 | } |
172 | |
173 | template<class CharType, class CharTrait, class T1, class T2> |
174 | inline std::basic_ostream<CharType, CharTrait>& |
175 | print(std::basic_ostream<CharType, CharTrait>& o, const cons<T1, T2>& t) { |
176 | |
177 | const CharType d = format_info::get_manipulator(o, format_info::delimiter); |
178 | |
179 | o << t.head; |
180 | |
181 | o << d; |
182 | |
183 | return print(o, t.tail); |
184 | } |
185 | |
186 | template<class CharT, class Traits, class T> |
187 | inline bool handle_width(std::basic_ostream<CharT, Traits>& o, const T& t) { |
188 | std::streamsize width = o.width(); |
189 | if(width == 0) return false; |
190 | |
191 | std::basic_ostringstream<CharT, Traits> ss; |
192 | |
193 | ss.copyfmt(o); |
194 | ss.tie(0); |
195 | ss.width(0); |
196 | |
197 | ss << t; |
198 | o << ss.str(); |
199 | |
200 | return true; |
201 | } |
202 | |
203 | |
204 | } // namespace detail |
205 | |
206 | |
207 | template<class CharType, class CharTrait> |
208 | inline std::basic_ostream<CharType, CharTrait>& |
209 | operator<<(std::basic_ostream<CharType, CharTrait>& o, |
210 | const null_type& t) { |
211 | if (!o.good() ) return o; |
212 | if (detail::handle_width(o, t)) return o; |
213 | |
214 | const CharType l = |
215 | detail::format_info::get_manipulator(o, detail::format_info::open); |
216 | const CharType r = |
217 | detail::format_info::get_manipulator(o, detail::format_info::close); |
218 | |
219 | o << l; |
220 | o << r; |
221 | |
222 | return o; |
223 | } |
224 | |
225 | template<class CharType, class CharTrait, class T1, class T2> |
226 | inline std::basic_ostream<CharType, CharTrait>& |
227 | operator<<(std::basic_ostream<CharType, CharTrait>& o, |
228 | const cons<T1, T2>& t) { |
229 | if (!o.good() ) return o; |
230 | if (detail::handle_width(o, t)) return o; |
231 | |
232 | const CharType l = |
233 | detail::format_info::get_manipulator(o, detail::format_info::open); |
234 | const CharType r = |
235 | detail::format_info::get_manipulator(o, detail::format_info::close); |
236 | |
237 | o << l; |
238 | |
239 | detail::print(o, t); |
240 | |
241 | o << r; |
242 | |
243 | return o; |
244 | } |
245 | |
246 | |
247 | // ------------------------------------------------------------- |
248 | // input stream operators |
249 | |
250 | namespace detail { |
251 | |
252 | |
253 | template<class CharType, class CharTrait> |
254 | inline std::basic_istream<CharType, CharTrait>& |
255 | extract_and_check_delimiter( |
256 | std::basic_istream<CharType, CharTrait> &is, format_info::manipulator_type del) |
257 | { |
258 | const CharType d = format_info::get_manipulator(is, del); |
259 | |
260 | #if defined (BOOST_NO_STD_LOCALE) |
261 | const bool is_delimiter = !isspace(d); |
262 | #elif defined ( __BORLANDC__ ) |
263 | const bool is_delimiter = !std::use_facet< std::ctype< CharType > > |
264 | (is.getloc() ).is( std::ctype_base::space, d); |
265 | #else |
266 | const bool is_delimiter = (!std::isspace(d, is.getloc()) ); |
267 | #endif |
268 | |
269 | CharType c; |
270 | if (is_delimiter) { |
271 | is >> c; |
272 | if (is.good() && c!=d) { |
273 | is.setstate(std::ios::failbit); |
274 | } |
275 | } else { |
276 | is >> std::ws; |
277 | } |
278 | return is; |
279 | } |
280 | |
281 | |
282 | template<class CharType, class CharTrait, class T1> |
283 | inline std::basic_istream<CharType, CharTrait> & |
284 | read (std::basic_istream<CharType, CharTrait> &is, cons<T1, null_type>& t1) { |
285 | |
286 | if (!is.good()) return is; |
287 | |
288 | return is >> t1.head; |
289 | } |
290 | |
291 | template<class CharType, class CharTrait, class T1, class T2> |
292 | inline std::basic_istream<CharType, CharTrait>& |
293 | read(std::basic_istream<CharType, CharTrait> &is, cons<T1, T2>& t1) { |
294 | |
295 | if (!is.good()) return is; |
296 | |
297 | is >> t1.head; |
298 | |
299 | |
300 | extract_and_check_delimiter(is, format_info::delimiter); |
301 | |
302 | return read(is, t1.tail); |
303 | } |
304 | |
305 | } // end namespace detail |
306 | |
307 | |
308 | template<class CharType, class CharTrait> |
309 | inline std::basic_istream<CharType, CharTrait>& |
310 | operator>>(std::basic_istream<CharType, CharTrait> &is, null_type&) { |
311 | |
312 | if (!is.good() ) return is; |
313 | |
314 | detail::extract_and_check_delimiter(is, detail::format_info::open); |
315 | detail::extract_and_check_delimiter(is, detail::format_info::close); |
316 | |
317 | return is; |
318 | } |
319 | |
320 | template<class CharType, class CharTrait, class T1, class T2> |
321 | inline std::basic_istream<CharType, CharTrait>& |
322 | operator>>(std::basic_istream<CharType, CharTrait>& is, cons<T1, T2>& t1) { |
323 | |
324 | if (!is.good() ) return is; |
325 | |
326 | detail::extract_and_check_delimiter(is, detail::format_info::open); |
327 | |
328 | detail::read(is, t1); |
329 | |
330 | detail::extract_and_check_delimiter(is, detail::format_info::close); |
331 | |
332 | return is; |
333 | } |
334 | |
335 | |
336 | } // end of namespace tuples |
337 | } // end of namespace boost |
338 | |
339 | #endif // BOOST_TUPLE_IO_HPP |
340 | |
341 | |
342 | |