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