Chris@16: // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) Chris@16: // (C) Copyright 2003-2007 Jonathan Turkanis Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) Chris@16: Chris@16: // See http://www.boost.org/libs/iostreams for documentation. Chris@16: Chris@16: // Contains: The function template copy, which reads data from a Source Chris@16: // and writes it to a Sink until the end of the sequence is reached, returning Chris@16: // the number of characters transfered. Chris@16: Chris@16: // The implementation is complicated by the need to handle smart adapters Chris@16: // and direct devices. Chris@16: Chris@16: #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED Chris@16: #define BOOST_IOSTREAMS_COPY_HPP_INCLUDED Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1020) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include // Make sure ptrdiff_t is in std. Chris@16: #include // copy, min. Chris@16: #include // ptrdiff_t. Chris@16: #include // pair. Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // failure, streamsize. Chris@16: #include Chris@16: #include Chris@16: #include // read, write, close. Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace iostreams { Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: // The following four overloads of copy_impl() optimize Chris@16: // copying in the case that one or both of the two devices Chris@16: // models Direct (see Chris@16: // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4) Chris@16: Chris@16: // Copy from a direct source to a direct sink Chris@16: template Chris@16: std::streamsize copy_impl( Source& src, Sink& snk, Chris@16: std::streamsize /* buffer_size */, Chris@16: mpl::true_, mpl::true_ ) Chris@16: { Chris@16: using namespace std; Chris@16: typedef typename char_type_of::type char_type; Chris@16: typedef std::pair pair_type; Chris@16: pair_type p1 = iostreams::input_sequence(src); Chris@16: pair_type p2 = iostreams::output_sequence(snk); Chris@16: std::streamsize total = Chris@16: static_cast( Chris@16: (std::min)(p1.second - p1.first, p2.second - p2.first) Chris@16: ); Chris@16: std::copy(p1.first, p1.first + total, p2.first); Chris@16: return total; Chris@16: } Chris@16: Chris@16: // Copy from a direct source to an indirect sink Chris@16: template Chris@16: std::streamsize copy_impl( Source& src, Sink& snk, Chris@16: std::streamsize /* buffer_size */, Chris@16: mpl::true_, mpl::false_ ) Chris@16: { Chris@16: using namespace std; Chris@16: typedef typename char_type_of::type char_type; Chris@16: typedef std::pair pair_type; Chris@16: pair_type p = iostreams::input_sequence(src); Chris@16: std::streamsize size, total; Chris@16: for ( total = 0, size = static_cast(p.second - p.first); Chris@16: total < size; ) Chris@16: { Chris@16: std::streamsize amt = Chris@16: iostreams::write(snk, p.first + total, size - total); Chris@16: total += amt; Chris@16: } Chris@16: return total; Chris@16: } Chris@16: Chris@16: // Copy from an indirect source to a direct sink Chris@16: template Chris@16: std::streamsize copy_impl( Source& src, Sink& snk, Chris@16: std::streamsize buffer_size, Chris@16: mpl::false_, mpl::true_ ) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: typedef std::pair pair_type; Chris@16: detail::basic_buffer buf(buffer_size); Chris@16: pair_type p = snk.output_sequence(); Chris@16: std::streamsize total = 0; Chris@16: std::ptrdiff_t capacity = p.second - p.first; Chris@16: while (true) { Chris@16: std::streamsize amt = Chris@16: iostreams::read( Chris@16: src, Chris@16: buf.data(), Chris@16: buffer_size < capacity - total ? Chris@16: buffer_size : Chris@16: static_cast(capacity - total) Chris@16: ); Chris@16: if (amt == -1) Chris@16: break; Chris@16: std::copy(buf.data(), buf.data() + amt, p.first + total); Chris@16: total += amt; Chris@16: } Chris@16: return total; Chris@16: } Chris@16: Chris@16: // Copy from an indirect source to an indirect sink Chris@16: template Chris@16: std::streamsize copy_impl( Source& src, Sink& snk, Chris@16: std::streamsize buffer_size, Chris@16: mpl::false_, mpl::false_ ) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: detail::basic_buffer buf(buffer_size); Chris@16: non_blocking_adapter nb(snk); Chris@16: std::streamsize total = 0; Chris@16: bool done = false; Chris@16: while (!done) { Chris@16: std::streamsize amt; Chris@16: done = (amt = iostreams::read(src, buf.data(), buffer_size)) == -1; Chris@16: if (amt != -1) { Chris@16: iostreams::write(nb, buf.data(), amt); Chris@16: total += amt; Chris@16: } Chris@16: } Chris@16: return total; Chris@16: } Chris@16: Chris@16: // The following function object is used with Chris@16: // boost::iostreams::detail::execute() in the primary Chris@16: // overload of copy_impl(), below Chris@16: Chris@16: // Function object that delegates to one of the above four Chris@16: // overloads of compl_impl() Chris@16: template Chris@16: class copy_operation { Chris@16: public: Chris@16: typedef std::streamsize result_type; Chris@16: copy_operation(Source& src, Sink& snk, std::streamsize buffer_size) Chris@16: : src_(src), snk_(snk), buffer_size_(buffer_size) Chris@16: { } Chris@16: std::streamsize operator()() Chris@16: { Chris@16: return copy_impl( src_, snk_, buffer_size_, Chris@16: is_direct(), is_direct() ); Chris@16: } Chris@16: private: Chris@16: copy_operation& operator=(const copy_operation&); Chris@16: Source& src_; Chris@16: Sink& snk_; Chris@16: std::streamsize buffer_size_; Chris@16: }; Chris@16: Chris@16: // Primary overload of copy_impl. Delegates to one of the above four Chris@16: // overloads of compl_impl(), depending on which of the two given Chris@16: // devices, if any, models Direct (see Chris@16: // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4) Chris@16: template Chris@16: std::streamsize copy_impl(Source src, Sink snk, std::streamsize buffer_size) Chris@16: { Chris@16: using namespace std; Chris@16: typedef typename char_type_of::type src_char; Chris@16: typedef typename char_type_of::type snk_char; Chris@16: BOOST_STATIC_ASSERT((is_same::value)); Chris@16: return detail::execute_all( Chris@16: copy_operation(src, snk, buffer_size), Chris@16: detail::call_close_all(src), Chris@16: detail::call_close_all(snk) Chris@16: ); Chris@16: } Chris@16: Chris@16: } // End namespace detail. Chris@16: Chris@16: //------------------Definition of copy----------------------------------------// Chris@16: Chris@16: // Overload of copy() for the case where neither the source nor the sink is Chris@16: // a standard stream or stream buffer Chris@16: template Chris@16: std::streamsize Chris@16: copy( const Source& src, const Sink& snk, Chris@16: std::streamsize buffer_size = default_device_buffer_size Chris@16: BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) Chris@16: BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) ) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: return detail::copy_impl( detail::resolve(src), Chris@16: detail::resolve(snk), Chris@16: buffer_size ); Chris@16: } Chris@16: Chris@16: #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //---------------------------------// Chris@16: Chris@16: // Overload of copy() for the case where the source, but not the sink, is Chris@16: // a standard stream or stream buffer Chris@16: template Chris@16: std::streamsize Chris@16: copy( Source& src, const Sink& snk, Chris@16: std::streamsize buffer_size = default_device_buffer_size Chris@16: BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) Chris@16: BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) ) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: return detail::copy_impl( detail::wrap(src), Chris@16: detail::resolve(snk), Chris@16: buffer_size ); Chris@16: } Chris@16: Chris@16: // Overload of copy() for the case where the sink, but not the source, is Chris@16: // a standard stream or stream buffer Chris@16: template Chris@16: std::streamsize Chris@16: copy( const Source& src, Sink& snk, Chris@16: std::streamsize buffer_size = default_device_buffer_size Chris@16: BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) Chris@16: BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) ) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: return detail::copy_impl( detail::resolve(src), Chris@16: detail::wrap(snk), buffer_size ); Chris@16: } Chris@16: Chris@16: // Overload of copy() for the case where neither the source nor the sink is Chris@16: // a standard stream or stream buffer Chris@16: template Chris@16: std::streamsize Chris@16: copy( Source& src, Sink& snk, Chris@16: std::streamsize buffer_size = default_device_buffer_size Chris@16: BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) Chris@16: BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) ) Chris@16: { Chris@16: return detail::copy_impl(detail::wrap(src), detail::wrap(snk), buffer_size); Chris@16: } Chris@16: Chris@16: #endif // #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //-----------------------// Chris@16: Chris@16: } } // End namespaces iostreams, boost. Chris@16: Chris@16: #endif // #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED