#include <string> #include <vector> #include <algorithm> #include <ios> #include <iostream> #include <boost/mpl/bool.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility/result_of.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/lexical_cast.hpp> #include <boost/iostreams/categories.hpp> #include <boost/iostreams/traits.hpp> #include <boost/iostreams/close.hpp> #include <boost/iostreams/device/back_inserter.hpp> #include <boost/iostreams/copy.hpp> template< class Char, class Traits = std::char_traits< Char > > class basic_ostreamable_source { private: typedef std::basic_string< Char, Traits > buffer_type; public: typedef Char char_type; struct category : public boost::iostreams::device_tag , public boost::iostreams::input {}; public: template< class T > explicit basic_ostreamable_source( T const &source ) : buf_( boost::lexical_cast< buffer_type >( source ) ) {} std::streamsize read( char_type *p, std::streamsize n ) { std::streamsize sz = std::min< std::streamsize >( buf_.size(), n ); { char_type const *p_src = buf_.c_str(); std::copy( p_src, p_src + sz, p ); } buf_.erase( buf_.begin(), buf_.begin() + sz ); return buf_.empty() && sz == 0 ? -1 : sz; } private: buffer_type buf_; }; // class basic_ostreamable_source typedef basic_ostreamable_source< char > ostreamable_source; template< class Source , class Traits = std::char_traits< typename boost::iostreams::char_type_of< Source >::type > > class source_sequence { public: typedef typename boost::iostreams::char_type_of< Source >::type char_type; struct category : public boost::iostreams::device_tag , public boost::iostreams::input , public boost::iostreams::closable_tag {}; private: typedef typename boost::iostreams::mode_of< Source >::type base_mode; typedef typename boost::is_convertible< base_mode, boost::iostreams::closable_tag >::type is_closable; typedef std::basic_string< char_type, Traits > string_type; typedef std::vector< Source > sequence_type; private: class impl { public: template< class SinglePassRange > impl( SinglePassRange const &sources , std::basic_string< char_type > const &delimiter ) : sequence_( boost::begin( sources ), boost::end( sources ) ) , curr_( sequence_.begin() ) , last_( sequence_.end() ) , delimiter_( delimiter ) , delim_curr_( delimiter_.end() ) {} std::streamsize read( char_type *p, std::streamsize const n ) { std::streamsize remain_sz = n; std::streamsize read_sz = 0; std::streamsize sz = std::min( delimiter_.end() - delim_curr_, n ); char_type const *p_src = delimiter_.c_str(); std::copy( p_src, p_src + sz, p ); p += sz; delim_curr_ += sz; remain_sz -= sz; read_sz += sz; if( delim_curr_ != delimiter_.end() ){ return sz; } sz = boost::iostreams::read( *curr_, p, remain_sz ); if( sz != -1 ){ read_sz += sz; return read_sz; } close_dispatch( is_closable() ); ++curr_; if( curr_ == last_ ){ return -1; } delim_curr_ = delimiter_.begin(); return read_sz; } void close() { for( ; curr_ != last_; ++curr_ ){ boost::iostreams::close( *curr_, std::ios_base::in ); } } private: void close_dispatch( boost::mpl::false_ /*is_closable*/ ) {} void close_dispatch( boost::mpl::true_ /*is_closable*/ ) { boost::iostreams::close( *curr_, std::ios_base::in ); } private: sequence_type sequence_; typename sequence_type::iterator curr_; typename sequence_type::iterator last_; string_type const delimiter_; typename string_type::const_iterator delim_curr_; }; // class impl public: template< class SinglePassRange > source_sequence( SinglePassRange const &sources , string_type const &delimiter ) : pimpl_( new impl( sources, delimiter ) ) {} // Compiler-generated cctor (with shallow copy semantics), dtor and // assignment are fine. std::streamsize read( char_type *p, std::streamsize n ) { return pimpl_->read( p, n ); } void close() { pimpl_->close(); } private: boost::shared_ptr< impl > pimpl_; }; // class source_sequence template< class SourceRange > source_sequence< typename boost::range_value< SourceRange >::type > make_source_sequence( SourceRange const &r , std::basic_string< typename boost::iostreams::char_type_of< typename boost::range_value< SourceRange >::type >::type , std::char_traits< typename boost::iostreams::char_type_of< typename boost::range_value< SourceRange >::type >::type > > const &delimiter ) { return source_sequence< typename boost::range_value< SourceRange >::type >( r, delimiter ); } template< class T > struct ctor { template< class FArgs > struct result : boost::mpl::identity< T > {}; template< class A0 > T operator()( A0 const &a0 ) const { return T( a0 ); } }; template< class SinglePassRange, class UnaryFunction > struct transform_iterator_reference : public boost::result_of< UnaryFunction( typename boost::iterator_reference< typename boost::range_result_iterator< SinglePassRange > > ) > {}; template< class SinglePassRange, class UnaryFunction > std::pair< boost::transform_iterator< UnaryFunction , typename boost::range_result_iterator< SinglePassRange >::type , typename transform_iterator_reference< SinglePassRange , UnaryFunction >::type > , boost::transform_iterator< UnaryFunction , typename boost::range_result_iterator< SinglePassRange >::type , typename transform_iterator_reference< SinglePassRange , UnaryFunction >::type > > transformed( SinglePassRange &r, UnaryFunction f ) { typedef boost::transform_iterator< UnaryFunction , typename boost::range_result_iterator< SinglePassRange >::type , typename transform_iterator_reference< SinglePassRange , UnaryFunction >::type > result_iterator; return std::pair< result_iterator, result_iterator >( result_iterator( boost::begin( r ), f ) , result_iterator( boost::end( r ), f ) ); } using namespace std; namespace io = boost::iostreams; int main() { vector< double > v; v.push_back( 1.23456 ); v.push_back( 0.00000321 ); v.push_back( 987654321 ); string str; io::copy( make_source_sequence( transformed( v , ctor< ostreamable_source >() ) , " <delim> " ) , io::back_inserter( str ) ); cout << str << endl; }