1 | // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) |
2 | // (C) Copyright 2003-2007 Jonathan Turkanis |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) |
5 | |
6 | // See http://www.boost.org/libs/iostreams for documentation. |
7 | |
8 | // Contains: The function template copy, which reads data from a Source |
9 | // and writes it to a Sink until the end of the sequence is reached, returning |
10 | // the number of characters transfered. |
11 | |
12 | // The implementation is complicated by the need to handle smart adapters |
13 | // and direct devices. |
14 | |
15 | #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED |
16 | #define BOOST_IOSTREAMS_COPY_HPP_INCLUDED |
17 | |
18 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
19 | # pragma once |
20 | #endif |
21 | |
22 | #include <boost/config.hpp> // Make sure ptrdiff_t is in std. |
23 | #include <algorithm> // copy, min. |
24 | #include <cstddef> // ptrdiff_t. |
25 | #include <utility> // pair. |
26 | #include <boost/bind.hpp> |
27 | #include <boost/detail/workaround.hpp> |
28 | #include <boost/iostreams/chain.hpp> |
29 | #include <boost/iostreams/constants.hpp> |
30 | #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp> |
31 | #include <boost/iostreams/detail/buffer.hpp> |
32 | #include <boost/iostreams/detail/enable_if_stream.hpp> |
33 | #include <boost/iostreams/detail/execute.hpp> |
34 | #include <boost/iostreams/detail/functional.hpp> |
35 | #include <boost/iostreams/detail/ios.hpp> // failure, streamsize. |
36 | #include <boost/iostreams/detail/resolve.hpp> |
37 | #include <boost/iostreams/detail/wrap_unwrap.hpp> |
38 | #include <boost/iostreams/operations.hpp> // read, write, close. |
39 | #include <boost/iostreams/pipeline.hpp> |
40 | #include <boost/static_assert.hpp> |
41 | #include <boost/type_traits/is_same.hpp> |
42 | |
43 | namespace boost { namespace iostreams { |
44 | |
45 | namespace detail { |
46 | |
47 | // The following four overloads of copy_impl() optimize |
48 | // copying in the case that one or both of the two devices |
49 | // models Direct (see |
50 | // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4) |
51 | |
52 | // Copy from a direct source to a direct sink |
53 | template<typename Source, typename Sink> |
54 | std::streamsize copy_impl( Source& src, Sink& snk, |
55 | std::streamsize /* buffer_size */, |
56 | mpl::true_, mpl::true_ ) |
57 | { |
58 | using namespace std; |
59 | typedef typename char_type_of<Source>::type char_type; |
60 | typedef std::pair<char_type*, char_type*> pair_type; |
61 | pair_type p1 = iostreams::input_sequence(src); |
62 | pair_type p2 = iostreams::output_sequence(snk); |
63 | std::streamsize total = |
64 | static_cast<std::streamsize>( |
65 | (std::min)(p1.second - p1.first, p2.second - p2.first) |
66 | ); |
67 | std::copy(p1.first, p1.first + total, p2.first); |
68 | return total; |
69 | } |
70 | |
71 | // Copy from a direct source to an indirect sink |
72 | template<typename Source, typename Sink> |
73 | std::streamsize copy_impl( Source& src, Sink& snk, |
74 | std::streamsize /* buffer_size */, |
75 | mpl::true_, mpl::false_ ) |
76 | { |
77 | using namespace std; |
78 | typedef typename char_type_of<Source>::type char_type; |
79 | typedef std::pair<char_type*, char_type*> pair_type; |
80 | pair_type p = iostreams::input_sequence(src); |
81 | std::streamsize size, total; |
82 | for ( total = 0, size = static_cast<std::streamsize>(p.second - p.first); |
83 | total < size; ) |
84 | { |
85 | std::streamsize amt = |
86 | iostreams::write(snk, p.first + total, size - total); |
87 | total += amt; |
88 | } |
89 | return total; |
90 | } |
91 | |
92 | // Copy from an indirect source to a direct sink |
93 | template<typename Source, typename Sink> |
94 | std::streamsize copy_impl( Source& src, Sink& snk, |
95 | std::streamsize buffer_size, |
96 | mpl::false_, mpl::true_ ) |
97 | { |
98 | typedef typename char_type_of<Source>::type char_type; |
99 | typedef std::pair<char_type*, char_type*> pair_type; |
100 | detail::basic_buffer<char_type> buf(buffer_size); |
101 | pair_type p = snk.output_sequence(); |
102 | std::streamsize total = 0; |
103 | std::ptrdiff_t capacity = p.second - p.first; |
104 | while (true) { |
105 | std::streamsize amt = |
106 | iostreams::read( |
107 | src, |
108 | buf.data(), |
109 | buffer_size < capacity - total ? |
110 | buffer_size : |
111 | static_cast<std::streamsize>(capacity - total) |
112 | ); |
113 | if (amt == -1) |
114 | break; |
115 | std::copy(buf.data(), buf.data() + amt, p.first + total); |
116 | total += amt; |
117 | } |
118 | return total; |
119 | } |
120 | |
121 | // Copy from an indirect source to an indirect sink |
122 | template<typename Source, typename Sink> |
123 | std::streamsize copy_impl( Source& src, Sink& snk, |
124 | std::streamsize buffer_size, |
125 | mpl::false_, mpl::false_ ) |
126 | { |
127 | typedef typename char_type_of<Source>::type char_type; |
128 | detail::basic_buffer<char_type> buf(buffer_size); |
129 | non_blocking_adapter<Sink> nb(snk); |
130 | std::streamsize total = 0; |
131 | bool done = false; |
132 | while (!done) { |
133 | std::streamsize amt; |
134 | done = (amt = iostreams::read(src, buf.data(), buffer_size)) == -1; |
135 | if (amt != -1) { |
136 | iostreams::write(nb, buf.data(), amt); |
137 | total += amt; |
138 | } |
139 | } |
140 | return total; |
141 | } |
142 | |
143 | // The following function object is used with |
144 | // boost::iostreams::detail::execute() in the primary |
145 | // overload of copy_impl(), below |
146 | |
147 | // Function object that delegates to one of the above four |
148 | // overloads of compl_impl() |
149 | template<typename Source, typename Sink> |
150 | class copy_operation { |
151 | public: |
152 | typedef std::streamsize result_type; |
153 | copy_operation(Source& src, Sink& snk, std::streamsize buffer_size) |
154 | : src_(src), snk_(snk), buffer_size_(buffer_size) |
155 | { } |
156 | std::streamsize operator()() |
157 | { |
158 | return copy_impl( src_, snk_, buffer_size_, |
159 | is_direct<Source>(), is_direct<Sink>() ); |
160 | } |
161 | private: |
162 | copy_operation& operator=(const copy_operation&); |
163 | Source& src_; |
164 | Sink& snk_; |
165 | std::streamsize buffer_size_; |
166 | }; |
167 | |
168 | // Primary overload of copy_impl. Delegates to one of the above four |
169 | // overloads of compl_impl(), depending on which of the two given |
170 | // devices, if any, models Direct (see |
171 | // http://www.boost.org/libs/iostreams/doc/index.html?path=4.1.1.4) |
172 | template<typename Source, typename Sink> |
173 | std::streamsize copy_impl(Source src, Sink snk, std::streamsize buffer_size) |
174 | { |
175 | using namespace std; |
176 | typedef typename char_type_of<Source>::type src_char; |
177 | typedef typename char_type_of<Sink>::type snk_char; |
178 | BOOST_STATIC_ASSERT((is_same<src_char, snk_char>::value)); |
179 | return detail::execute_all( |
180 | copy_operation<Source, Sink>(src, snk, buffer_size), |
181 | detail::call_close_all(src), |
182 | detail::call_close_all(snk) |
183 | ); |
184 | } |
185 | |
186 | } // End namespace detail. |
187 | |
188 | //------------------Definition of copy----------------------------------------// |
189 | |
190 | // Overload of copy() for the case where neither the source nor the sink is |
191 | // a standard stream or stream buffer |
192 | template<typename Source, typename Sink> |
193 | std::streamsize |
194 | copy( const Source& src, const Sink& snk, |
195 | std::streamsize buffer_size = default_device_buffer_size |
196 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) |
197 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) ) |
198 | { |
199 | typedef typename char_type_of<Source>::type char_type; |
200 | return detail::copy_impl( detail::resolve<input, char_type>(src), |
201 | detail::resolve<output, char_type>(snk), |
202 | buffer_size ); |
203 | } |
204 | |
205 | #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //---------------------------------// |
206 | |
207 | // Overload of copy() for the case where the source, but not the sink, is |
208 | // a standard stream or stream buffer |
209 | template<typename Source, typename Sink> |
210 | std::streamsize |
211 | copy( Source& src, const Sink& snk, |
212 | std::streamsize buffer_size = default_device_buffer_size |
213 | BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) |
214 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(Sink) ) |
215 | { |
216 | typedef typename char_type_of<Source>::type char_type; |
217 | return detail::copy_impl( detail::wrap(src), |
218 | detail::resolve<output, char_type>(snk), |
219 | buffer_size ); |
220 | } |
221 | |
222 | // Overload of copy() for the case where the sink, but not the source, is |
223 | // a standard stream or stream buffer |
224 | template<typename Source, typename Sink> |
225 | std::streamsize |
226 | copy( const Source& src, Sink& snk, |
227 | std::streamsize buffer_size = default_device_buffer_size |
228 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(Source) |
229 | BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) ) |
230 | { |
231 | typedef typename char_type_of<Source>::type char_type; |
232 | return detail::copy_impl( detail::resolve<input, char_type>(src), |
233 | detail::wrap(snk), buffer_size ); |
234 | } |
235 | |
236 | // Overload of copy() for the case where neither the source nor the sink is |
237 | // a standard stream or stream buffer |
238 | template<typename Source, typename Sink> |
239 | std::streamsize |
240 | copy( Source& src, Sink& snk, |
241 | std::streamsize buffer_size = default_device_buffer_size |
242 | BOOST_IOSTREAMS_ENABLE_IF_STREAM(Source) |
243 | BOOST_IOSTREAMS_ENABLE_IF_STREAM(Sink) ) |
244 | { |
245 | return detail::copy_impl(detail::wrap(src), detail::wrap(snk), buffer_size); |
246 | } |
247 | |
248 | #endif // #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) //-----------------------// |
249 | |
250 | } } // End namespaces iostreams, boost. |
251 | |
252 | #endif // #ifndef BOOST_IOSTREAMS_COPY_HPP_INCLUDED |
253 | |