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