// (C) Copyright Jonathan Turkanis 2004. // 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. // Disclaimer: Not a Boost library. #ifndef BOOST_IOSTREAMS_CONTAINER_IO_HPP_INCLUDED #define BOOST_IOSTREAMS_CONTAINER_IO_HPP_INCLUDED #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace io { namespace detail { template void expect_string( std::basic_istream& in, const std::locale& loc, const std::basic_string& str ) { using namespace std; typedef typename basic_string::const_iterator iterator; iterator first = str.begin(); iterator last = str.end(); // Skip ws. while (first != last && isspace(*first, loc)) ++first; in >> ws; // Compare sequences. while (first != last) if (*first++ != in.get()) { in.clear(ios::failbit); break; } } // Returns true if beginning of in contains sep, ignoring leading whitespace, // and false otherwise. If beggining of in contains neither sep nor close, // sets failbit. template bool expect_string( std::basic_istream& in, const std::locale& loc, const std::basic_string& sep, const std::basic_string& close ) { using namespace std; typedef typename basic_string::const_iterator iterator; // Loop variables. iterator sep_first = sep.begin(); iterator sep_last = sep.end(); iterator close_first = close.begin(); iterator close_last = close.end(); bool not_sep = false; bool not_close = false; // Skip ws. while (sep_first != sep_last && isspace(*sep_first, loc)) { ++sep_first; if (sep_first == sep_last) not_sep = true; } while (close_first != close_last && isspace(*close_first, loc)) { ++close_first; if (close_first == close_last) not_close = true; } in >> ws; // Compare sequences. while (!not_sep || !not_close) { Ch sep_char = not_sep ? Ch() : *sep_first; Ch close_char = not_close ? Ch() : *close_first; Ch in_char = in.get(); if (!not_sep && sep_char != in_char) not_sep = true; if (!not_close && close_char != in_char) not_close = true; if (!not_sep) { if (++sep_first == sep_last) return true; } if (!not_close) { if (++close_first == close_last) return false; } } in.clear(ios::failbit); return false; } //------------------Definition of format_impl---------------------------------// // Contains machinery for writing whitespace. struct format_impl_base { template static void post_open( std::basic_ostream& out, const punctuation& punc, indentation& ind ) { if (punc.flags() & punc::indent_after_open) ind.push(punc.tabs(), punc.spaces()); if ( out.good() && !ind.is_flat() && ( punc.flags() & punc::break_after_open ) != 0 ) { out << "\n"; ind.indent(out); } } template static void pre_sep( std::basic_ostream& out, const punctuation& punc, indentation& ind ) { if ( out.good() && !ind.is_flat() && (punc.flags() & punc::break_before_sep) != 0 ) { out << "\n"; ind.indent(out); } } template static void post_sep( std::basic_ostream& out, const punctuation& punc, indentation& ind ) { if ( out.good() && !ind.is_flat() && (punc.flags() & punc::break_after_sep) != 0 ) { out << "\n"; ind.indent(out); } } template static void pre_close( std::basic_ostream& out, const punctuation& punc, indentation& ind ) { if (punc.flags() & punc::indent_after_open) ind.pop(); if ( out.good() && !ind.is_flat() && ( punc.flags() & punc::break_before_close ) != 0 ) { out << "\n"; ind.indent(out); } } }; //------------------Definition of formatted i/o for ranges--------------------// template<> struct format_impl : format_impl_base { template static void write(std::basic_ostream& out, const Insertable& ins) { typedef typename range_const_iterator::type iterator; punctuation punc = get_punctuation(out, ins); indentation& ind = get_indentation(out); if (!(punc.flags() & punc::has_break)) ind.flatten(); out << punc.open(); post_open(out, punc, ind); bool first_time = true; for ( iterator first = begin(ins), second = end(ins); first != second && out.good(); ++first, first_time = false ) { if (!first_time) { pre_sep(out, punc, ind); out << punc.sep(); post_sep(out, punc, ind); } ind.inc(); if ( is_single_pass_range::value || is_tuple_like::value ) { boost::io::output_container(out, *first); } else { out << *first; } ind.dec(); } pre_close(out, punc, ind); out << punc.close(); } template static void read(std::basic_istream& in, Extractable& ext) { typedef typename range_value::type value_type; typedef typename is_basic_string::type is_string; read(in, ext, is_string()); } template static void read( std::basic_istream& in, Extractable& ext, mpl::true_ ) { using namespace std; typedef typename range_value::type string_type; locale loc = in.getloc(); punctuation punc = get_punctuation(in, ext); clear(in); expect_string(in, loc, punc.open()); for (bool done = false; in && !done;) { string_type str; done = !input_string(in, str, punc.sep(), punc.close()); if (in) insert(ext, end(ext), str); } } template static void read( std::basic_istream& in, Extractable& ext, mpl::false_ ) { using namespace std; typedef typename range_value::type basic_value_type; typedef typename mpl::eval_if< is_tuple_like, tuple_remove_const, mpl::identity >::type value_type; locale loc = in.getloc(); punctuation punc = get_punctuation(in, ext); clear(in); expect_string(in, loc, punc.open()); do { value_type v; boost::io::input_container(in, v); if (in) insert(ext, end(ext), v); } while (in && expect_string(in, loc, punc.sep(), punc.close())); } }; //------------------Definition of formatted i/o for tuples--------------------// template<> struct format_impl : format_impl_base { // Output functions template static void write(std::basic_ostream& out, const Insertable& ins) { typedef typename tuple_size::type size; punctuation punc = get_punctuation(out, ins); indentation& ind = get_indentation(out); out << punc.open(); post_open(out, punc, ind); if (size::value > 0 && out.good()) write_n(out, ins, punc, mpl::int_<0>()); pre_close(out, punc, ind); out << punc.close(); } template static void write_n( std::basic_ostream& out, const Insertable& ins, const punctuation& punc, mpl::int_ i ) { typedef typename tuple_size::type size; indentation& ind = get_indentation(out); ind.inc(); if (is_tuple_like::value) boost::io::output_container(out, tuple_get(ins)); else out << tuple_get(ins); ind.dec(); write_next(out, ins, punc, i, mpl::bool_< N + 1 < size::value >()); } template static void write_next( std::basic_ostream& out, const Insertable& ins, const punctuation& punc, mpl::int_, mpl::true_ ) { if (out) { indentation& ind = get_indentation(out); pre_sep(out, punc, ind); out << punc.template nth_sep(); post_sep(out, punc, ind); write_n(out, ins, punc, mpl::int_()); } } template static void write_next( std::basic_ostream&, const Insertable&, const punctuation&, mpl::int_, mpl::false_ ) { } // Input functions template static void read(std::basic_istream& in, Extractable& ext) { typedef typename tuple_size::type size; typedef typename tuple_element::type last; std::locale loc = in.getloc(); punctuation punc = get_punctuation(in, ext); expect_string(in, loc, punc.open()); if (size::value > 0 && in.good()) read_nth(in, ext, loc, punc, mpl::int_<0>()); if (!is_basic_string::value) expect_string(in, loc, punc.close()); } template static void read_nth( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_ n ) { typedef typename tuple_element::type value_type; typedef typename is_basic_string::type is_string; read_nth(in, ext, loc, punc, n, is_string()); } template static void read_nth( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_ n, mpl::true_ ) { typedef typename tuple_size::type size; std::basic_string sep = N == size::value - 1 ? punc.close() : punc.template nth_sep(); boost::io::detail::input_string(in, tuple_get(ext), sep); read_next(in, ext, loc, punc, n, mpl::bool_< N + 1 < size::value >()); } template static void read_nth( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_ n, mpl::false_ ) { typedef typename tuple_size::type size; in >> tuple_get(ext); read_next(in, ext, loc, punc, n, mpl::bool_< N + 1 < size::value >()); } template static void read_next( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_ n, mpl::true_ t ) { typedef typename tuple_element::type value_type; typedef typename is_basic_string::type is_string; read_next(in, ext, loc, punc, n, t, is_string()); } template static void read_next( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_, mpl::true_, mpl::true_ ) { if (in) read_nth(in, ext, loc, punc, mpl::int_()); } template static void read_next( std::basic_istream& in, Extractable& ext, const std::locale& loc, const punctuation& punc, mpl::int_, mpl::true_, mpl::false_ ) { if (in) { expect_string(in, loc, punc.template nth_sep()); read_nth(in, ext, loc, punc, mpl::int_()); } } template static void read_next( std::basic_istream&, Extractable&, const std::locale&, const punctuation&, mpl::int_, mpl::false_ ) { } }; } // End namespace detail. template std::basic_ostream& output_container(std::basic_ostream& out, const T& t) { typedef boost::io::is_single_pass_range is_range; typedef boost::io::detail::format_impl impl; impl::write(out, t); return out; } template std::basic_istream& input_container(std::basic_istream& in, T& t) { typedef boost::io::is_single_pass_range is_range; typedef boost::io::detail::format_impl impl; impl::read(in, t); return in; } } // End namespace io. } // End namespace boost. namespace std { template typename boost::enable_if< boost::mpl::or_< boost::io::is_single_pass_range, boost::io::is_tuple_like >, std::basic_ostream& >::type operator<<( std::basic_ostream& out, const Insertable& i ) { return boost::io::output_container(out, i); } template typename boost::enable_if< boost::mpl::or_< boost::io::is_extensible_range, boost::io::is_tuple_like >, std::basic_istream& >::type operator>>( std::basic_istream& in, Extractable& e ) { return boost::io::input_container(in, e); } } // End namespace std. #endif // #ifndef BOOST_IOSTREAMS_CONTAINER_IO_HPP_INCLUDED