1 // tuple_io.hpp --------------------------------------------------------------
3 // Copyright (C) 2001 Jaakko Järvi (jaakko.jarvi@cs.utu.fi)
4 // 2001 Gary Powell (gary.powell@sierra.com)
6 // Permission to copy, use, sell and distribute this software is granted
7 // provided this copyright notice appears in all copies.
8 // Permission to modify the code and to distribute modified code is granted
9 // provided this copyright notice appears in all copies, and a notice
10 // that the code was modified is included with the copyright notice.
12 // This software is provided "as is" without express or implied warranty,
13 // and with no claim as to its suitability for any purpose.
14 // For more information, see http://www.boost.org
16 // ----------------------------------------------------------------------------
18 #ifndef BOOST_TUPLE_IO_HPP
19 #define BOOST_TUPLE_IO_HPP
22 // add to boost/config.hpp
25 # if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97)
26 #define BOOST_NO_TEMPLATED_STREAMS
30 #if defined BOOST_NO_TEMPLATED_STREAMS
37 #include "boost/tuple/tuple.hpp"
39 // This is ugly: one should be using twoargument isspace since whitspace can
40 // be locale dependent, in theory at least.
41 // not all libraries implement have the two-arg version, so we need to
42 // use the one-arg one, which one should get with <cctype> but there seem
43 // to be exceptions to this.
45 #if !defined (BOOST_NO_STD_LOCALE)
47 #include <locale> // for two-arg isspace
51 #include <cctype> // for one-arg (old) isspace
52 #include <ctype.h> // Metrowerks does not find one-arg isspace from cctype
64 enum manipulator_type { open, close, delimiter };
65 BOOST_STATIC_CONSTANT(int, number_of_manipulators = delimiter + 1);
68 static int get_stream_index (int m)
70 static const int stream_index[number_of_manipulators]
71 = { std::ios::xalloc(), std::ios::xalloc(), std::ios::xalloc() };
73 return stream_index[m];
76 format_info(const format_info&);
82 #if defined (BOOST_NO_TEMPLATED_STREAMS)
83 static char get_manipulator(std::ios& i, manipulator_type m) {
84 char c = static_cast<char>(i.iword(get_stream_index(m)));
86 // parentheses and space are the default manipulators
89 case open : c = '('; break;
90 case close : c = ')'; break;
91 case delimiter : c = ' '; break;
97 static void set_manipulator(std::ios& i, manipulator_type m, char c) {
98 i.iword(get_stream_index(m)) = static_cast<long>(c);
101 template<class CharType, class CharTrait>
102 static CharType get_manipulator(std::basic_ios<CharType, CharTrait>& i,
103 manipulator_type m) {
104 // The manipulators are stored as long.
105 // A valid instanitation of basic_stream allows CharType to be any POD,
106 // hence, the static_cast may fail (it fails if long is not convertible
108 CharType c = static_cast<CharType>(i.iword(get_stream_index(m)) );
109 // parentheses and space are the default manipulators
112 case open : c = i.widen('('); break;
113 case close : c = i.widen(')'); break;
114 case delimiter : c = i.widen(' '); break;
121 template<class CharType, class CharTrait>
122 static void set_manipulator(std::basic_ios<CharType, CharTrait>& i,
123 manipulator_type m, CharType c) {
124 // The manipulators are stored as long.
125 // A valid instanitation of basic_stream allows CharType to be any POD,
126 // hence, the static_cast may fail (it fails if CharType is not
128 i.iword(get_stream_index(m)) = static_cast<long>(c);
130 #endif // BOOST_NO_TEMPLATED_STREAMS
133 } // end of namespace detail
135 template<class CharType>
136 class tuple_manipulator {
137 const detail::format_info::manipulator_type mt;
140 explicit tuple_manipulator(detail::format_info::manipulator_type m,
144 #if defined (BOOST_NO_TEMPLATED_STREAMS)
145 void set(std::ios &io) const {
146 detail::format_info::set_manipulator(io, mt, f_c);
149 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
150 template<class CharType2, class CharTrait>
151 void set(std::basic_ios<CharType2, CharTrait> &io) const {
152 detail::format_info::set_manipulator(io, mt, f_c);
155 template<class CharTrait>
156 void set(std::basic_ios<CharType, CharTrait> &io) const {
157 detail::format_info::set_manipulator(io, mt, f_c);
159 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
160 #endif // BOOST_NO_TEMPLATED_STREAMS
163 #if defined (BOOST_NO_TEMPLATED_STREAMS)
165 operator<<(std::ostream& o, const tuple_manipulator<char>& m) {
171 operator>>(std::istream& i, const tuple_manipulator<char>& m) {
178 template<class CharType, class CharTrait>
179 inline std::basic_ostream<CharType, CharTrait>&
180 operator<<(std::basic_ostream<CharType, CharTrait>& o, const tuple_manipulator<CharType>& m) {
185 template<class CharType, class CharTrait>
186 inline std::basic_istream<CharType, CharTrait>&
187 operator>>(std::basic_istream<CharType, CharTrait>& i, const tuple_manipulator<CharType>& m) {
192 #endif // BOOST_NO_TEMPLATED_STREAMS
194 template<class CharType>
195 inline tuple_manipulator<CharType> set_open(const CharType c) {
196 return tuple_manipulator<CharType>(detail::format_info::open, c);
199 template<class CharType>
200 inline tuple_manipulator<CharType> set_close(const CharType c) {
201 return tuple_manipulator<CharType>(detail::format_info::close, c);
204 template<class CharType>
205 inline tuple_manipulator<CharType> set_delimiter(const CharType c) {
206 return tuple_manipulator<CharType>(detail::format_info::delimiter, c);
213 // -------------------------------------------------------------
214 // printing tuples to ostream in format (a b c)
215 // parentheses and space are defaults, but can be overriden with manipulators
216 // set_open, set_close and set_delimiter
220 // Note: The order of the print functions is critical
221 // to let a conforming compiler find and select the correct one.
223 #if defined (BOOST_NO_TEMPLATED_STREAMS)
225 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
227 inline std::ostream& print(std::ostream& o, const cons<T1, null_type>& t) {
230 #endif // BOOST_NO_TEMPLATED_STREAMS
232 inline std::ostream& print(std::ostream& o, const null_type&) { return o; }
234 template<class T1, class T2>
236 print(std::ostream& o, const cons<T1, T2>& t) {
238 const char d = format_info::get_manipulator(o, format_info::delimiter);
242 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
243 if (tuples::length<T2>::value == 0)
245 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
248 return print(o, t.tail );
256 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
257 template<class CharType, class CharTrait, class T1>
258 inline std::basic_ostream<CharType, CharTrait>&
259 print(std::basic_ostream<CharType, CharTrait>& o, const cons<T1, null_type>& t) {
262 #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
265 template<class CharType, class CharTrait>
266 inline std::basic_ostream<CharType, CharTrait>&
267 print(std::basic_ostream<CharType, CharTrait>& o, const null_type&) {
271 template<class CharType, class CharTrait, class T1, class T2>
272 inline std::basic_ostream<CharType, CharTrait>&
273 print(std::basic_ostream<CharType, CharTrait>& o, const cons<T1, T2>& t) {
275 const CharType d = format_info::get_manipulator(o, format_info::delimiter);
279 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
280 if (tuples::length<T2>::value == 0)
282 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
285 return print(o, t.tail);
288 #endif // BOOST_NO_TEMPLATED_STREAMS
290 } // namespace detail
292 #if defined (BOOST_NO_TEMPLATED_STREAMS)
293 template<class T1, class T2>
294 inline std::ostream& operator<<(std::ostream& o, const cons<T1, T2>& t) {
295 if (!o.good() ) return o;
298 detail::format_info::get_manipulator(o, detail::format_info::open);
300 detail::format_info::get_manipulator(o, detail::format_info::close);
313 template<class CharType, class CharTrait, class T1, class T2>
314 inline std::basic_ostream<CharType, CharTrait>&
315 operator<<(std::basic_ostream<CharType, CharTrait>& o,
316 const cons<T1, T2>& t) {
317 if (!o.good() ) return o;
320 detail::format_info::get_manipulator(o, detail::format_info::open);
322 detail::format_info::get_manipulator(o, detail::format_info::close);
332 #endif // BOOST_NO_TEMPLATED_STREAMS
335 // -------------------------------------------------------------
336 // input stream operators
340 #if defined (BOOST_NO_TEMPLATED_STREAMS)
343 extract_and_check_delimiter(
344 std::istream& is, format_info::manipulator_type del)
346 const char d = format_info::get_manipulator(is, del);
348 #if defined (BOOST_NO_STD_LOCALE)
349 const bool is_delimiter = !isspace(d);
351 const bool is_delimiter = (!std::isspace(d, is.getloc()) );
358 is.setstate(std::ios::failbit);
365 // Note: The order of the read functions is critical to let a
366 // (conforming?) compiler find and select the correct one.
368 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
370 inline std::istream &
371 read (std::istream &is, cons<T1, null_type>& t1) {
373 if (!is.good()) return is;
375 return is >> t1.head ;
378 inline std::istream& read(std::istream& i, const null_type&) { return i; }
379 #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
381 template<class T1, class T2>
383 read(std::istream &is, cons<T1, T2>& t1) {
385 if (!is.good()) return is;
389 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
390 if (tuples::length<T2>::value == 0)
392 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
394 extract_and_check_delimiter(is, format_info::delimiter);
396 return read(is, t1.tail);
399 } // end namespace detail
402 operator>>(std::istream &is, null_type&) {
404 if (!is.good() ) return is;
406 detail::extract_and_check_delimiter(is, detail::format_info::open);
407 detail::extract_and_check_delimiter(is, detail::format_info::close);
413 template<class T1, class T2>
415 operator>>(std::istream& is, cons<T1, T2>& t1) {
417 if (!is.good() ) return is;
419 detail::extract_and_check_delimiter(is, detail::format_info::open);
421 detail::read(is, t1);
423 detail::extract_and_check_delimiter(is, detail::format_info::close);
432 template<class CharType, class CharTrait>
433 inline std::basic_istream<CharType, CharTrait>&
434 extract_and_check_delimiter(
435 std::basic_istream<CharType, CharTrait> &is, format_info::manipulator_type del)
437 const CharType d = format_info::get_manipulator(is, del);
439 #if defined (BOOST_NO_STD_LOCALE)
440 const bool is_delimiter = !isspace(d);
442 const bool is_delimiter = (!std::isspace(d, is.getloc()) );
449 is.setstate(std::ios::failbit);
456 #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
457 template<class CharType, class CharTrait, class T1>
458 inline std::basic_istream<CharType, CharTrait> &
459 read (std::basic_istream<CharType, CharTrait> &is, cons<T1, null_type>& t1) {
461 if (!is.good()) return is;
463 return is >> t1.head;
466 template<class CharType, class CharTrait>
467 inline std::basic_istream<CharType, CharTrait>&
468 read(std::basic_istream<CharType, CharTrait>& i, const null_type&) { return i; }
470 #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
472 template<class CharType, class CharTrait, class T1, class T2>
473 inline std::basic_istream<CharType, CharTrait>&
474 read(std::basic_istream<CharType, CharTrait> &is, cons<T1, T2>& t1) {
476 if (!is.good()) return is;
480 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
481 if (tuples::length<T2>::value == 0)
483 #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
485 extract_and_check_delimiter(is, format_info::delimiter);
487 return read(is, t1.tail);
490 } // end namespace detail
493 template<class CharType, class CharTrait>
494 inline std::basic_istream<CharType, CharTrait>&
495 operator>>(std::basic_istream<CharType, CharTrait> &is, null_type&) {
497 if (!is.good() ) return is;
499 detail::extract_and_check_delimiter(is, detail::format_info::open);
500 detail::extract_and_check_delimiter(is, detail::format_info::close);
505 template<class CharType, class CharTrait, class T1, class T2>
506 inline std::basic_istream<CharType, CharTrait>&
507 operator>>(std::basic_istream<CharType, CharTrait>& is, cons<T1, T2>& t1) {
509 if (!is.good() ) return is;
511 detail::extract_and_check_delimiter(is, detail::format_info::open);
513 detail::read(is, t1);
515 detail::extract_and_check_delimiter(is, detail::format_info::close);
520 #endif // BOOST_NO_TEMPLATED_STREAMS
522 } // end of namespace tuples
523 } // end of namespace boost
525 #endif // BOOST_TUPLE_IO_HPP