Range の Source 化

#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;
}