sl@0: // tuple_io.hpp -------------------------------------------------------------- sl@0: sl@0: // Copyright (C) 2001 Jaakko Järvi (jaakko.jarvi@cs.utu.fi) sl@0: // 2001 Gary Powell (gary.powell@sierra.com) sl@0: // sl@0: // Distributed under the Boost Software License, Version 1.0. (See sl@0: // accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: // For more information, see http://www.boost.org sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: sl@0: #ifndef BOOST_TUPLE_IO_HPP sl@0: #define BOOST_TUPLE_IO_HPP sl@0: sl@0: sl@0: // add to boost/config.hpp sl@0: // for now sl@0: # if defined __GNUC__ sl@0: # if (__GNUC__ == 2 && __GNUC_MINOR__ <= 97) sl@0: #define BOOST_NO_TEMPLATED_STREAMS sl@0: #endif sl@0: #endif // __GNUC__ sl@0: sl@0: #if defined BOOST_NO_TEMPLATED_STREAMS sl@0: #include sl@0: #else sl@0: #include sl@0: #include sl@0: #endif sl@0: sl@0: #include "boost/tuple/tuple.hpp" sl@0: sl@0: // This is ugly: one should be using twoargument isspace since whitspace can sl@0: // be locale dependent, in theory at least. sl@0: // not all libraries implement have the two-arg version, so we need to sl@0: // use the one-arg one, which one should get with but there seem sl@0: // to be exceptions to this. sl@0: sl@0: #if !defined (BOOST_NO_STD_LOCALE) sl@0: sl@0: #include // for two-arg isspace sl@0: sl@0: #else sl@0: sl@0: #include // for one-arg (old) isspace sl@0: #include // Metrowerks does not find one-arg isspace from cctype sl@0: sl@0: #endif sl@0: sl@0: namespace boost { sl@0: namespace tuples { sl@0: sl@0: namespace detail { sl@0: sl@0: class format_info { sl@0: public: sl@0: sl@0: enum manipulator_type { open, close, delimiter }; sl@0: BOOST_STATIC_CONSTANT(int, number_of_manipulators = delimiter + 1); sl@0: private: sl@0: sl@0: static int get_stream_index (int m) sl@0: { sl@0: static const int stream_index[number_of_manipulators] sl@0: = { std::ios::xalloc(), std::ios::xalloc(), std::ios::xalloc() }; sl@0: sl@0: return stream_index[m]; sl@0: } sl@0: sl@0: format_info(const format_info&); sl@0: format_info(); sl@0: sl@0: sl@0: public: sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: static char get_manipulator(std::ios& i, manipulator_type m) { sl@0: char c = static_cast(i.iword(get_stream_index(m))); sl@0: sl@0: // parentheses and space are the default manipulators sl@0: if (!c) { sl@0: switch(m) { sl@0: case detail::format_info::open : c = '('; break; sl@0: case detail::format_info::close : c = ')'; break; sl@0: case detail::format_info::delimiter : c = ' '; break; sl@0: } sl@0: } sl@0: return c; sl@0: } sl@0: sl@0: static void set_manipulator(std::ios& i, manipulator_type m, char c) { sl@0: i.iword(get_stream_index(m)) = static_cast(c); sl@0: } sl@0: #else sl@0: template sl@0: static CharType get_manipulator(std::basic_ios& i, sl@0: manipulator_type m) { sl@0: // The manipulators are stored as long. sl@0: // A valid instanitation of basic_stream allows CharType to be any POD, sl@0: // hence, the static_cast may fail (it fails if long is not convertible sl@0: // to CharType sl@0: CharType c = static_cast(i.iword(get_stream_index(m)) ); sl@0: // parentheses and space are the default manipulators sl@0: if (!c) { sl@0: switch(m) { sl@0: case detail::format_info::open : c = i.widen('('); break; sl@0: case detail::format_info::close : c = i.widen(')'); break; sl@0: case detail::format_info::delimiter : c = i.widen(' '); break; sl@0: } sl@0: } sl@0: return c; sl@0: } sl@0: sl@0: sl@0: template sl@0: static void set_manipulator(std::basic_ios& i, sl@0: manipulator_type m, CharType c) { sl@0: // The manipulators are stored as long. sl@0: // A valid instanitation of basic_stream allows CharType to be any POD, sl@0: // hence, the static_cast may fail (it fails if CharType is not sl@0: // convertible long. sl@0: i.iword(get_stream_index(m)) = static_cast(c); sl@0: } sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: }; sl@0: sl@0: } // end of namespace detail sl@0: sl@0: template sl@0: class tuple_manipulator { sl@0: const detail::format_info::manipulator_type mt; sl@0: CharType f_c; sl@0: public: sl@0: explicit tuple_manipulator(detail::format_info::manipulator_type m, sl@0: const char c = 0) sl@0: : mt(m), f_c(c) {} sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: void set(std::ios &io) const { sl@0: detail::format_info::set_manipulator(io, mt, f_c); sl@0: } sl@0: #else sl@0: #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: template sl@0: void set(std::basic_ios &io) const { sl@0: detail::format_info::set_manipulator(io, mt, f_c); sl@0: } sl@0: #else sl@0: template sl@0: void set(std::basic_ios &io) const { sl@0: detail::format_info::set_manipulator(io, mt, f_c); sl@0: } sl@0: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: }; sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: inline std::ostream& sl@0: operator<<(std::ostream& o, const tuple_manipulator& m) { sl@0: m.set(o); sl@0: return o; sl@0: } sl@0: sl@0: inline std::istream& sl@0: operator>>(std::istream& i, const tuple_manipulator& m) { sl@0: m.set(i); sl@0: return i; sl@0: } sl@0: sl@0: #else sl@0: sl@0: template sl@0: inline std::basic_ostream& sl@0: operator<<(std::basic_ostream& o, const tuple_manipulator& m) { sl@0: m.set(o); sl@0: return o; sl@0: } sl@0: sl@0: template sl@0: inline std::basic_istream& sl@0: operator>>(std::basic_istream& i, const tuple_manipulator& m) { sl@0: m.set(i); sl@0: return i; sl@0: } sl@0: sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: sl@0: template sl@0: inline tuple_manipulator set_open(const CharType c) { sl@0: return tuple_manipulator(detail::format_info::open, c); sl@0: } sl@0: sl@0: template sl@0: inline tuple_manipulator set_close(const CharType c) { sl@0: return tuple_manipulator(detail::format_info::close, c); sl@0: } sl@0: sl@0: template sl@0: inline tuple_manipulator set_delimiter(const CharType c) { sl@0: return tuple_manipulator(detail::format_info::delimiter, c); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: // ------------------------------------------------------------- sl@0: // printing tuples to ostream in format (a b c) sl@0: // parentheses and space are defaults, but can be overriden with manipulators sl@0: // set_open, set_close and set_delimiter sl@0: sl@0: namespace detail { sl@0: sl@0: // Note: The order of the print functions is critical sl@0: // to let a conforming compiler find and select the correct one. sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: sl@0: #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: template sl@0: inline std::ostream& print(std::ostream& o, const cons& t) { sl@0: return o << t.head; sl@0: } sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: sl@0: inline std::ostream& print(std::ostream& o, const null_type&) { return o; } sl@0: sl@0: template sl@0: inline std::ostream& sl@0: print(std::ostream& o, const cons& t) { sl@0: sl@0: const char d = format_info::get_manipulator(o, format_info::delimiter); sl@0: sl@0: o << t.head; sl@0: sl@0: #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: if (tuples::length::value == 0) sl@0: return o; sl@0: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: o << d; sl@0: sl@0: return print(o, t.tail ); sl@0: sl@0: } sl@0: sl@0: sl@0: sl@0: #else sl@0: sl@0: #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: template sl@0: inline std::basic_ostream& sl@0: print(std::basic_ostream& o, const cons& t) { sl@0: return o << t.head; sl@0: } sl@0: #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: sl@0: sl@0: template sl@0: inline std::basic_ostream& sl@0: print(std::basic_ostream& o, const null_type&) { sl@0: return o; sl@0: } sl@0: sl@0: template sl@0: inline std::basic_ostream& sl@0: print(std::basic_ostream& o, const cons& t) { sl@0: sl@0: const CharType d = format_info::get_manipulator(o, format_info::delimiter); sl@0: sl@0: o << t.head; sl@0: sl@0: #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: if (tuples::length::value == 0) sl@0: return o; sl@0: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: o << d; sl@0: sl@0: return print(o, t.tail); sl@0: } sl@0: sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: sl@0: } // namespace detail sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: template sl@0: inline std::ostream& operator<<(std::ostream& o, const cons& t) { sl@0: if (!o.good() ) return o; sl@0: sl@0: const char l = sl@0: detail::format_info::get_manipulator(o, detail::format_info::open); sl@0: const char r = sl@0: detail::format_info::get_manipulator(o, detail::format_info::close); sl@0: sl@0: o << l; sl@0: sl@0: detail::print(o, t); sl@0: sl@0: o << r; sl@0: sl@0: return o; sl@0: } sl@0: sl@0: #else sl@0: sl@0: template sl@0: inline std::basic_ostream& sl@0: operator<<(std::basic_ostream& o, sl@0: const cons& t) { sl@0: if (!o.good() ) return o; sl@0: sl@0: const CharType l = sl@0: detail::format_info::get_manipulator(o, detail::format_info::open); sl@0: const CharType r = sl@0: detail::format_info::get_manipulator(o, detail::format_info::close); sl@0: sl@0: o << l; sl@0: sl@0: detail::print(o, t); sl@0: sl@0: o << r; sl@0: sl@0: return o; sl@0: } sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: sl@0: sl@0: // ------------------------------------------------------------- sl@0: // input stream operators sl@0: sl@0: namespace detail { sl@0: sl@0: #if defined (BOOST_NO_TEMPLATED_STREAMS) sl@0: sl@0: inline std::istream& sl@0: extract_and_check_delimiter( sl@0: std::istream& is, format_info::manipulator_type del) sl@0: { sl@0: const char d = format_info::get_manipulator(is, del); sl@0: sl@0: #if defined (BOOST_NO_STD_LOCALE) sl@0: const bool is_delimiter = !isspace(d); sl@0: #else sl@0: const bool is_delimiter = (!std::isspace(d, is.getloc()) ); sl@0: #endif sl@0: sl@0: char c; sl@0: if (is_delimiter) { sl@0: is >> c; sl@0: if (is.good() && c!=d) { sl@0: is.setstate(std::ios::failbit); sl@0: } sl@0: } sl@0: return is; sl@0: } sl@0: sl@0: sl@0: // Note: The order of the read functions is critical to let a sl@0: // (conforming?) compiler find and select the correct one. sl@0: sl@0: #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: template sl@0: inline std::istream & sl@0: read (std::istream &is, cons& t1) { sl@0: sl@0: if (!is.good()) return is; sl@0: sl@0: return is >> t1.head ; sl@0: } sl@0: #else sl@0: inline std::istream& read(std::istream& i, const null_type&) { return i; } sl@0: #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: sl@0: template sl@0: inline std::istream& sl@0: read(std::istream &is, cons& t1) { sl@0: sl@0: if (!is.good()) return is; sl@0: sl@0: is >> t1.head; sl@0: sl@0: #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: if (tuples::length::value == 0) sl@0: return is; sl@0: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: sl@0: extract_and_check_delimiter(is, format_info::delimiter); sl@0: sl@0: return read(is, t1.tail); sl@0: } sl@0: sl@0: } // end namespace detail sl@0: sl@0: inline std::istream& sl@0: operator>>(std::istream &is, null_type&) { sl@0: sl@0: if (!is.good() ) return is; sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::open); sl@0: detail::extract_and_check_delimiter(is, detail::format_info::close); sl@0: sl@0: return is; sl@0: } sl@0: sl@0: sl@0: template sl@0: inline std::istream& sl@0: operator>>(std::istream& is, cons& t1) { sl@0: sl@0: if (!is.good() ) return is; sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::open); sl@0: sl@0: detail::read(is, t1); sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::close); sl@0: sl@0: return is; sl@0: } sl@0: sl@0: sl@0: sl@0: #else sl@0: sl@0: template sl@0: inline std::basic_istream& sl@0: extract_and_check_delimiter( sl@0: std::basic_istream &is, format_info::manipulator_type del) sl@0: { sl@0: const CharType d = format_info::get_manipulator(is, del); sl@0: sl@0: #if defined (BOOST_NO_STD_LOCALE) sl@0: const bool is_delimiter = !isspace(d); sl@0: #elif defined ( __BORLANDC__ ) sl@0: const bool is_delimiter = !std::use_facet< std::ctype< CharType > > sl@0: (is.getloc() ).is( std::ctype_base::space, d); sl@0: #else sl@0: const bool is_delimiter = (!std::isspace(d, is.getloc()) ); sl@0: #endif sl@0: sl@0: CharType c; sl@0: if (is_delimiter) { sl@0: is >> c; sl@0: if (is.good() && c!=d) { sl@0: is.setstate(std::ios::failbit); sl@0: } sl@0: } sl@0: return is; sl@0: } sl@0: sl@0: sl@0: #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: template sl@0: inline std::basic_istream & sl@0: read (std::basic_istream &is, cons& t1) { sl@0: sl@0: if (!is.good()) return is; sl@0: sl@0: return is >> t1.head; sl@0: } sl@0: #else sl@0: template sl@0: inline std::basic_istream& sl@0: read(std::basic_istream& i, const null_type&) { return i; } sl@0: sl@0: #endif // !BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: sl@0: template sl@0: inline std::basic_istream& sl@0: read(std::basic_istream &is, cons& t1) { sl@0: sl@0: if (!is.good()) return is; sl@0: sl@0: is >> t1.head; sl@0: sl@0: #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) sl@0: if (tuples::length::value == 0) sl@0: return is; sl@0: #endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION sl@0: sl@0: extract_and_check_delimiter(is, format_info::delimiter); sl@0: sl@0: return read(is, t1.tail); sl@0: } sl@0: sl@0: } // end namespace detail sl@0: sl@0: sl@0: template sl@0: inline std::basic_istream& sl@0: operator>>(std::basic_istream &is, null_type&) { sl@0: sl@0: if (!is.good() ) return is; sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::open); sl@0: detail::extract_and_check_delimiter(is, detail::format_info::close); sl@0: sl@0: return is; sl@0: } sl@0: sl@0: template sl@0: inline std::basic_istream& sl@0: operator>>(std::basic_istream& is, cons& t1) { sl@0: sl@0: if (!is.good() ) return is; sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::open); sl@0: sl@0: detail::read(is, t1); sl@0: sl@0: detail::extract_and_check_delimiter(is, detail::format_info::close); sl@0: sl@0: return is; sl@0: } sl@0: sl@0: #endif // BOOST_NO_TEMPLATED_STREAMS sl@0: sl@0: } // end of namespace tuples sl@0: } // end of namespace boost sl@0: sl@0: #endif // BOOST_TUPLE_IO_HPP sl@0: sl@0: