| [12] | 1 | // (C) Copyright Jonathan Turkanis 2003. | 
|---|
 | 2 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | 
|---|
 | 3 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) | 
|---|
 | 4 |  | 
|---|
 | 5 | // See http://www.boost.org/libs/iostreams for documentation. | 
|---|
 | 6 |  | 
|---|
 | 7 | // Contains: The function template copy, which reads data from a Source  | 
|---|
 | 8 | // and writes it to a Sink until the end of the sequence is reached, returning  | 
|---|
 | 9 | // the number of characters transfered. | 
|---|
 | 10 |  | 
|---|
 | 11 | // The implementation is complicated by the need to handle smart adapters | 
|---|
 | 12 | // and direct devices. | 
|---|
 | 13 |  | 
|---|
 | 14 | #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED | 
|---|
 | 15 | #define BOOST_IOSTREAMS_COPY_HPP_INCLUDED | 
|---|
 | 16 |  | 
|---|
 | 17 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) | 
|---|
 | 18 | # pragma once | 
|---|
 | 19 | #endif               | 
|---|
 | 20 |  | 
|---|
 | 21 | #include <algorithm>                        // copy. | 
|---|
 | 22 | #include <utility>                          // pair. | 
|---|
 | 23 | #include <boost/detail/workaround.hpp> | 
|---|
 | 24 | #include <boost/iostreams/chain.hpp> | 
|---|
 | 25 | #include <boost/iostreams/constants.hpp> | 
|---|
 | 26 | #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>         | 
|---|
 | 27 | #include <boost/iostreams/detail/buffer.hpp>        | 
|---|
 | 28 | #include <boost/iostreams/detail/closer.hpp>     | 
|---|
 | 29 | #include <boost/iostreams/detail/enable_if_stream.hpp>   | 
|---|
 | 30 | #include <boost/iostreams/detail/ios.hpp>   // failure, streamsize.                    | 
|---|
 | 31 | #include <boost/iostreams/detail/resolve.hpp>                    | 
|---|
 | 32 | #include <boost/iostreams/detail/wrap_unwrap.hpp> | 
|---|
 | 33 | #include <boost/iostreams/operations.hpp>  // read, write, close. | 
|---|
 | 34 | #include <boost/iostreams/pipeline.hpp> | 
|---|
 | 35 | #include <boost/static_assert.hpp>   | 
|---|
 | 36 | #include <boost/type_traits/is_same.hpp>  | 
|---|
 | 37 |  | 
|---|
 | 38 | namespace boost { namespace iostreams { | 
|---|
 | 39 |  | 
|---|
 | 40 | namespace detail { | 
|---|
 | 41 |  | 
|---|
 | 42 | template<typename Source, typename Sink> | 
|---|
 | 43 | std::streamsize copy_impl( Source& src, Sink& snk,  | 
|---|
 | 44 |                            std::streamsize /* buffer_size */, | 
|---|
 | 45 |                            mpl::true_, mpl::true_ ) | 
|---|
 | 46 | {   // Copy from a direct Source to a direct Sink. | 
|---|
 | 47 |     using namespace std; | 
|---|
 | 48 |     typedef typename char_type_of<Source>::type  char_type; | 
|---|
 | 49 |     typedef pair<char_type*, char_type*>         pair_type; | 
|---|
 | 50 |     pair_type p1 = iostreams::input_sequence(src); | 
|---|
 | 51 |     pair_type p2 = iostreams::output_sequence(snk); | 
|---|
 | 52 |     if (p1.second - p1.first < p2.second - p2.first) { | 
|---|
 | 53 |         std::copy(p1.first, p1.second, p2.first); | 
|---|
 | 54 |         return static_cast<streamsize>(p1.second - p1.first); | 
|---|
 | 55 |     } else { | 
|---|
 | 56 |         throw BOOST_IOSTREAMS_FAILURE("destination too small"); | 
|---|
 | 57 |     } | 
|---|
 | 58 | } | 
|---|
 | 59 |  | 
|---|
 | 60 | template<typename Source, typename Sink> | 
|---|
 | 61 | std::streamsize copy_impl( Source& src, Sink& snk,  | 
|---|
 | 62 |                            std::streamsize /* buffer_size */, | 
|---|
 | 63 |                            mpl::true_, mpl::false_ ) | 
|---|
 | 64 | {   // Copy from a direct Source to an indirect Sink. | 
|---|
 | 65 |     using namespace std; | 
|---|
 | 66 |     typedef typename char_type_of<Source>::type  char_type; | 
|---|
 | 67 |     typedef pair<char_type*, char_type*>         pair_type; | 
|---|
 | 68 |     pair_type p = iostreams::input_sequence(src); | 
|---|
 | 69 |     std::streamsize size, total; | 
|---|
 | 70 |     for ( total = 0, size = static_cast<streamsize>(p.second - p.first); | 
|---|
 | 71 |           total < size; ) | 
|---|
 | 72 |     { | 
|---|
 | 73 |         std::streamsize amt =  | 
|---|
 | 74 |             iostreams::write(snk, p.first + total, size - total);  | 
|---|
 | 75 |         total += amt; | 
|---|
 | 76 |     } | 
|---|
 | 77 |     return size; | 
|---|
 | 78 | } | 
|---|
 | 79 |  | 
|---|
 | 80 | template<typename Source, typename Sink> | 
|---|
 | 81 | std::streamsize copy_impl( Source& src, Sink& snk,  | 
|---|
 | 82 |                            std::streamsize buffer_size, | 
|---|
 | 83 |                            mpl::false_, mpl::true_ ) | 
|---|
 | 84 | {   // Copy from an indirect Source to a direct Sink. | 
|---|
 | 85 |     using namespace std; | 
|---|
 | 86 |     typedef typename char_type_of<Source>::type  char_type; | 
|---|
 | 87 |     typedef pair<char_type*, char_type*>         pair_type; | 
|---|
 | 88 |     detail::basic_buffer<char_type>  buf(buffer_size); | 
|---|
 | 89 |     pair_type                        p = snk.output_sequence(); | 
|---|
 | 90 |     streamsize                       total = 0; | 
|---|
 | 91 |     bool                             done  = false; | 
|---|
 | 92 |     while (!done) { | 
|---|
 | 93 |         streamsize amt; | 
|---|
 | 94 |         done = (amt = iostreams::read(src, buf.data(), buffer_size)) == -1; | 
|---|
 | 95 |         std::copy(buf.data(), buf.data() + amt, p.first + total); | 
|---|
 | 96 |         if (amt != -1) | 
|---|
 | 97 |             total += amt; | 
|---|
 | 98 |     } | 
|---|
 | 99 |     return total; | 
|---|
 | 100 | } | 
|---|
 | 101 |  | 
|---|
 | 102 | template<typename Source, typename Sink> | 
|---|
 | 103 | std::streamsize copy_impl( Source& src, Sink& snk,  | 
|---|
 | 104 |                            std::streamsize buffer_size, | 
|---|
 | 105 |                            mpl::false_, mpl::false_ ) | 
|---|
 | 106 | {   // Copy from an indirect Source to a indirect Sink. This algorithm | 
|---|
 | 107 |     // can be improved by eliminating the non_blocking_adapter. | 
|---|
 | 108 |     typedef typename char_type_of<Source>::type char_type; | 
|---|
 | 109 |     detail::basic_buffer<char_type>  buf(buffer_size); | 
|---|
 | 110 |     non_blocking_adapter<Sink>       nb(snk); | 
|---|
 | 111 |     std::streamsize                  total = 0; | 
|---|
 | 112 |     bool                             done = false; | 
|---|
 | 113 |     while (!done) { | 
|---|
 | 114 |         std::streamsize amt; | 
|---|
 | 115 |         done = (amt = iostreams::read(src, buf.data(), buffer_size)) == -1; | 
|---|
 | 116 |         if (amt != -1) { | 
|---|
 | 117 |             iostreams::write(nb, buf.data(), amt); | 
|---|
 | 118 |             total += amt; | 
|---|
 | 119 |         } | 
|---|
 | 120 |     } | 
|---|
 | 121 |     return total; | 
|---|
 | 122 | } | 
|---|
 | 123 |  | 
|---|
 | 124 | template<typename Source, typename Sink> | 
|---|
 | 125 | std::streamsize copy_impl(Source src, Sink snk, std::streamsize buffer_size) | 
|---|
 | 126 | { | 
|---|
 | 127 |     using namespace std; | 
|---|
 | 128 |     typedef typename char_type_of<Source>::type  src_char; | 
|---|
 | 129 |     typedef typename char_type_of<Sink>::type    snk_char; | 
|---|
 | 130 |     BOOST_STATIC_ASSERT((is_same<src_char, snk_char>::value)); | 
|---|
 | 131 |     bool                     nothrow = false; | 
|---|
 | 132 |     external_closer<Source>  close_source(src, BOOST_IOS::in, nothrow); | 
|---|
 | 133 |     external_closer<Sink>    close_sink(snk, BOOST_IOS::out, nothrow); | 
|---|
 | 134 |     streamsize result = | 
|---|
 | 135 |         copy_impl( src, snk, buffer_size,  | 
|---|
 | 136 |                    is_direct<Source>(), is_direct<Sink>() ); | 
|---|
 | 137 |     return result;  | 
|---|
 | 138 | } | 
|---|
 | 139 |  | 
|---|
 | 140 | } // End namespace detail. | 
|---|
 | 141 |                      | 
|---|
 | 142 | //------------------Definition of copy----------------------------------------// | 
|---|
 | 143 |  | 
|---|
 | 144 | template<typename Source, typename Sink> | 
|---|
 | 145 | std::streamsize | 
|---|
 | 146 | copy( const Source& src, const Sink& snk, | 
|---|
 | 147 |       std::streamsize buffer_size = default_device_buffer_size | 
|---|
 | 148 |       BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) | 
|---|
 | 149 |       BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) ) | 
|---|
 | 150 | {  | 
|---|
 | 151 |     typedef typename char_type_of<Source>::type char_type; | 
|---|
 | 152 |     return detail::copy_impl( detail::resolve<input, char_type>(src),  | 
|---|
 | 153 |                               detail::resolve<output, char_type>(snk),  | 
|---|
 | 154 |                               buffer_size );  | 
|---|
 | 155 | } | 
|---|
 | 156 |  | 
|---|
 | 157 | #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //---------------------------------// | 
|---|
 | 158 |  | 
|---|
 | 159 | template<typename Source, typename Sink> | 
|---|
 | 160 | std::streamsize | 
|---|
 | 161 | copy( Source& src, const Sink& snk, | 
|---|
 | 162 |       std::streamsize buffer_size = default_device_buffer_size | 
|---|
 | 163 |       BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) | 
|---|
 | 164 |       BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) )  | 
|---|
 | 165 | {  | 
|---|
 | 166 |     typedef typename char_type_of<Source>::type char_type; | 
|---|
 | 167 |     return detail::copy_impl( detail::wrap(src),  | 
|---|
 | 168 |                               detail::resolve<output, char_type>(snk),  | 
|---|
 | 169 |                               buffer_size ); | 
|---|
 | 170 | } | 
|---|
 | 171 |  | 
|---|
 | 172 | template<typename Source, typename Sink> | 
|---|
 | 173 | std::streamsize | 
|---|
 | 174 | copy( const Source& src, Sink& snk, | 
|---|
 | 175 |       std::streamsize buffer_size = default_device_buffer_size | 
|---|
 | 176 |       BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) | 
|---|
 | 177 |       BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) )  | 
|---|
 | 178 | {  | 
|---|
 | 179 |     typedef typename char_type_of<Source>::type char_type; | 
|---|
 | 180 |     return detail::copy_impl( detail::resolve<input, char_type>(src),  | 
|---|
 | 181 |                               detail::wrap(snk), buffer_size); | 
|---|
 | 182 | } | 
|---|
 | 183 |  | 
|---|
 | 184 | template<typename Source, typename Sink> | 
|---|
 | 185 | std::streamsize | 
|---|
 | 186 | copy( Source& src, Sink& snk, | 
|---|
 | 187 |       std::streamsize buffer_size = default_device_buffer_size | 
|---|
 | 188 |       BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) | 
|---|
 | 189 |       BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) )  | 
|---|
 | 190 | {  | 
|---|
 | 191 |     return detail::copy_impl(detail::wrap(src), detail::wrap(snk), buffer_size); | 
|---|
 | 192 | } | 
|---|
 | 193 |  | 
|---|
 | 194 | #endif // #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //-----------------------// | 
|---|
 | 195 |  | 
|---|
 | 196 | } } // End namespaces iostreams, boost. | 
|---|
 | 197 |  | 
|---|
 | 198 | #endif // #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED | 
|---|