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