| 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 | 
|---|