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