|
1 // (C) Copyright Jonathan Turkanis 2005. |
|
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 // Note: bidirectional streams are not supported. |
|
8 |
|
9 #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED |
|
10 #define BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED |
|
11 |
|
12 #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
|
13 # pragma once |
|
14 #endif |
|
15 |
|
16 #include <algorithm> // min. |
|
17 #include <utility> // pair. |
|
18 #include <boost/config.hpp> // DEDUCED_TYPENAME. |
|
19 #include <boost/iostreams/categories.hpp> |
|
20 #include <boost/iostreams/detail/adapter/direct_adapter.hpp> |
|
21 #include <boost/iostreams/detail/call_traits.hpp> |
|
22 #include <boost/iostreams/detail/closer.hpp> |
|
23 #include <boost/iostreams/detail/enable_if_stream.hpp> |
|
24 #include <boost/iostreams/operations.hpp> |
|
25 #include <boost/iostreams/traits.hpp> // mode_of, is_direct. |
|
26 #include <boost/mpl/if.hpp> |
|
27 #include <boost/ref.hpp> |
|
28 #include <boost/static_assert.hpp> |
|
29 #include <boost/type_traits/is_convertible.hpp> |
|
30 |
|
31 namespace boost { namespace iostreams { |
|
32 |
|
33 namespace detail { |
|
34 |
|
35 template<typename Filter, typename Device> |
|
36 struct composite_mode { |
|
37 typedef typename mode_of<Filter>::type filter_mode; |
|
38 typedef typename mode_of<Device>::type device_mode; |
|
39 typedef is_convertible<filter_mode, dual_use> is_dual_use; |
|
40 typedef typename |
|
41 mpl::if_< |
|
42 is_convertible<device_mode, input>, |
|
43 input, |
|
44 output |
|
45 >::type type; |
|
46 }; |
|
47 |
|
48 // |
|
49 // Template name: composite_device. |
|
50 // Description: Provides a Device view of a Filter, Device pair. |
|
51 // Template paramters: |
|
52 // Filter - A model of Filter. |
|
53 // Device - An indirect model of Device. |
|
54 // |
|
55 template< typename Filter, |
|
56 typename Device, |
|
57 typename Mode = |
|
58 BOOST_DEDUCED_TYPENAME composite_mode<Filter, Device>::type > |
|
59 class composite_device { |
|
60 private: |
|
61 typedef typename detail::param_type<Device>::type param_type; |
|
62 typedef typename |
|
63 iostreams::select< // Disambiguation for Tru64. |
|
64 is_direct<Device>, direct_adapter<Device>, |
|
65 is_std_io<Device>, Device&, |
|
66 else_, Device |
|
67 >::type value_type; |
|
68 public: |
|
69 typedef typename char_type_of<Filter>::type char_type; |
|
70 struct category |
|
71 : Mode, |
|
72 device_tag, |
|
73 closable_tag, |
|
74 flushable_tag, |
|
75 localizable_tag, |
|
76 optimally_buffered_tag |
|
77 { }; |
|
78 composite_device(const Filter& flt, param_type dev); |
|
79 std::streamsize read(char_type* s, std::streamsize n); |
|
80 std::streamsize write(const char_type* s, std::streamsize n); |
|
81 stream_offset seek( stream_offset off, BOOST_IOS::seekdir way, |
|
82 BOOST_IOS::openmode which = |
|
83 BOOST_IOS::in | BOOST_IOS::out ); |
|
84 |
|
85 void close(); |
|
86 void close(BOOST_IOS::openmode which); |
|
87 bool flush(); |
|
88 std::streamsize optimal_buffer_size() const; |
|
89 |
|
90 template<typename Locale> // Avoid dependency on <locale> |
|
91 void imbue(const Locale& loc) |
|
92 { |
|
93 iostreams::imbue(filter_, loc); |
|
94 iostreams::imbue(device_, loc); |
|
95 } |
|
96 |
|
97 Filter& first() { return filter_; } |
|
98 Device& second() { return device_; } |
|
99 private: |
|
100 Filter filter_; |
|
101 value_type device_; |
|
102 }; |
|
103 |
|
104 // |
|
105 // Template name: composite_device. |
|
106 // Description: Provides a Device view of a Filter, Device pair. |
|
107 // Template paramters: |
|
108 // Filter - A model of Filter. |
|
109 // Device - An indirect model of Device. |
|
110 // |
|
111 template<typename Filter1, typename Filter2> |
|
112 class composite_filter { |
|
113 private: |
|
114 typedef reference_wrapper<Filter2> filter_ref; |
|
115 public: |
|
116 typedef typename char_type_of<Filter1>::type char_type; |
|
117 struct category |
|
118 : mode_of<Filter1>::type, |
|
119 filter_tag, |
|
120 multichar_tag, |
|
121 closable_tag, |
|
122 flushable_tag, |
|
123 localizable_tag, |
|
124 optimally_buffered_tag |
|
125 { }; |
|
126 composite_filter(const Filter1& filter1, const Filter2& filter2) |
|
127 : filter1_(filter1), filter2_(filter2) |
|
128 { } |
|
129 |
|
130 template<typename Source> |
|
131 std::streamsize read(Source& src, char_type* s, std::streamsize n) |
|
132 { |
|
133 composite_device<filter_ref, Source> cmp(boost::ref(filter2_), src); |
|
134 return iostreams::read(filter1_, cmp, s, n); |
|
135 } |
|
136 |
|
137 template<typename Sink> |
|
138 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n) |
|
139 { |
|
140 composite_device<filter_ref, Sink> cmp(boost::ref(filter2_), snk); |
|
141 return iostreams::write(filter1_, cmp, s, n); |
|
142 } |
|
143 |
|
144 template<typename Device> |
|
145 stream_offset seek( Device& dev, stream_offset off, BOOST_IOS::seekdir way, |
|
146 BOOST_IOS::openmode which = |
|
147 BOOST_IOS::in | BOOST_IOS::out ) |
|
148 { |
|
149 composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev); |
|
150 return iostreams::seek(filter1_, cmp, off, way, which); |
|
151 } |
|
152 |
|
153 template<typename Device> |
|
154 void close( Device& dev, |
|
155 BOOST_IOS::openmode which = |
|
156 BOOST_IOS::in | BOOST_IOS::out ) |
|
157 { |
|
158 composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev); |
|
159 iostreams::close(filter1_, cmp, which); |
|
160 } |
|
161 |
|
162 template<typename Device> |
|
163 bool flush(Device& dev) |
|
164 { |
|
165 composite_device<Filter2, Device> cmp(filter2_, dev); |
|
166 return iostreams::flush(filter1_, cmp); |
|
167 } |
|
168 |
|
169 std::streamsize optimal_buffer_size() const |
|
170 { |
|
171 std::streamsize first = iostreams::optimal_buffer_size(filter1_); |
|
172 std::streamsize second = iostreams::optimal_buffer_size(filter2_); |
|
173 return first < second ? second : first; |
|
174 } |
|
175 |
|
176 template<typename Locale> // Avoid dependency on <locale> |
|
177 void imbue(const Locale& loc) |
|
178 { // To do: consider using RAII. |
|
179 iostreams::imbue(filter1_, loc); |
|
180 iostreams::imbue(filter2_, loc); |
|
181 } |
|
182 |
|
183 Filter1& first() { return filter1_; } |
|
184 Filter2& second() { return filter2_; } |
|
185 private: |
|
186 Filter1 filter1_; |
|
187 Filter2 filter2_; |
|
188 }; |
|
189 |
|
190 template<typename Filter, typename FilterOrDevice> |
|
191 struct composite_traits |
|
192 : mpl::if_< |
|
193 is_device<FilterOrDevice>, |
|
194 composite_device<Filter, FilterOrDevice>, |
|
195 composite_filter<Filter, FilterOrDevice> |
|
196 > |
|
197 { }; |
|
198 |
|
199 } // End namespace detail. |
|
200 |
|
201 template<typename Filter, typename FilterOrDevice> |
|
202 struct composite : detail::composite_traits<Filter, FilterOrDevice>::type { |
|
203 typedef typename detail::param_type<FilterOrDevice>::type param_type; |
|
204 typedef typename detail::composite_traits<Filter, FilterOrDevice>::type base; |
|
205 composite(const Filter& flt, param_type dev) |
|
206 : base(flt, dev) |
|
207 { } |
|
208 }; |
|
209 |
|
210 //--------------Implementation of compose-------------------------------------// |
|
211 |
|
212 // Note: The following workarounds are patterned after resolve.hpp. It has not |
|
213 // yet been confirmed that they are necessary. |
|
214 |
|
215 #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //-------------------------// |
|
216 # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //-------------------------------// |
|
217 |
|
218 template<typename Filter, typename FilterOrDevice> |
|
219 composite<Filter, FilterOrDevice> |
|
220 compose( const Filter& filter, const FilterOrDevice& fod |
|
221 BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) ) |
|
222 { return composite<Filter, FilterOrDevice>(filter, fod); } |
|
223 |
|
224 template<typename Filter, typename Ch, typename Tr> |
|
225 composite< Filter, std::basic_streambuf<Ch, Tr> > |
|
226 compose(const Filter& filter, std::basic_streambuf<Ch, Tr>& sb) |
|
227 { return composite< Filter, std::basic_streambuf<Ch, Tr> >(filter, sb); } |
|
228 |
|
229 template<typename Filter, typename Ch, typename Tr> |
|
230 composite< Filter, std::basic_istream<Ch, Tr> > |
|
231 compose(const Filter& filter, std::basic_istream<Ch, Tr>& is) |
|
232 { return composite< Filter, std::basic_istream<Ch, Tr> >(filter, is); } |
|
233 |
|
234 template<typename Filter, typename Ch, typename Tr> |
|
235 composite< Filter, std::basic_ostream<Ch, Tr> > |
|
236 compose(const Filter& filter, std::basic_ostream<Ch, Tr>& os) |
|
237 { return composite< Filter, std::basic_ostream<Ch, Tr> >(filter, os); } |
|
238 |
|
239 template<typename Filter, typename Ch, typename Tr> |
|
240 composite< Filter, std::basic_iostream<Ch, Tr> > |
|
241 compose(const Filter& filter, std::basic_iostream<Ch, Tr>& io) |
|
242 { return composite< Filter, std::basic_iostream<Ch, Tr> >(filter, io); } |
|
243 |
|
244 # else // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //---------------------// |
|
245 |
|
246 template<typename Filter, typename FilterOrDevice> |
|
247 composite<Filter, FilterOrDevice> |
|
248 compose( const Filter& filter, const FilterOrDevice& fod |
|
249 BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) ) |
|
250 { return composite<Filter, FilterOrDevice>(filter, fod); } |
|
251 |
|
252 template<typename Filter> |
|
253 composite<Filter, std::streambuf> |
|
254 compose(const Filter& filter, std::streambuf& sb) |
|
255 { return composite<Filter, std::streambuf>(filter, sb); } |
|
256 |
|
257 template<typename Filter> |
|
258 composite<Filter, std::istream> |
|
259 compose(const Filter& filter, std::istream& is) |
|
260 { return composite<Filter, std::istream>(filter, is); } |
|
261 |
|
262 template<typename Filter> |
|
263 composite<Filter, std::ostream> |
|
264 compose(const Filter& filter, std::ostream& os) |
|
265 { return composite<Filter, std::ostream>(filter, os); } |
|
266 |
|
267 template<typename Filter> |
|
268 composite<Filter, std::iostream> |
|
269 compose(const Filter& filter, std::iostream& io) |
|
270 { return composite<Filter, std::iostream>(filter, io); } |
|
271 |
|
272 # endif // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //--------------------// |
|
273 #else // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //----------------// |
|
274 |
|
275 template<typename Filter, typename Stream> |
|
276 composite<Filter, Stream> |
|
277 compose(const Filter& flt, const Stream& strm, mpl::true_) |
|
278 { // Bad overload resolution. |
|
279 return composite<Filter, Stream>(flt, const_cast<Stream&>(strm)); |
|
280 } |
|
281 |
|
282 template<typename Filter, typename FilterOrDevice> |
|
283 composite<Filter, FilterOrDevice> |
|
284 compose(const Filter& flt, const FilterOrDevice& fod, mpl::false_) |
|
285 { return composite<Filter, FilterOrDevice>(flt, fod); } |
|
286 |
|
287 template<typename Filter, typename FilterOrDevice> |
|
288 composite<Filter, FilterOrDevice> |
|
289 compose( const Filter& flt, const FilterOrDevice& fod |
|
290 BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) ) |
|
291 { return compose(flt, fod, is_std_io<FilterOrDevice>()); } |
|
292 |
|
293 # if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \ |
|
294 !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && \ |
|
295 !defined(__GNUC__) // ---------------------------------------------------// |
|
296 |
|
297 template<typename Filter, typename FilterOrDevice> |
|
298 composite<Filter, FilterOrDevice> |
|
299 compose (const Filter& filter, FilterOrDevice& fod) |
|
300 { return composite<Filter, FilterOrDevice>(filter, fod); } |
|
301 |
|
302 # endif // Borland 5.x, VC6-7.0 or GCC 2.9x //--------------------------------// |
|
303 #endif // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //---------------// |
|
304 |
|
305 //----------------------------------------------------------------------------// |
|
306 |
|
307 namespace detail { |
|
308 |
|
309 //--------------Implementation of composite_device---------------------------// |
|
310 |
|
311 template<typename Filter, typename Device, typename Mode> |
|
312 composite_device<Filter, Device, Mode>::composite_device |
|
313 (const Filter& flt, param_type dev) |
|
314 : filter_(flt), device_(dev) |
|
315 { } |
|
316 |
|
317 template<typename Filter, typename Device, typename Mode> |
|
318 inline std::streamsize composite_device<Filter, Device, Mode>::read |
|
319 (char_type* s, std::streamsize n) |
|
320 { return iostreams::read(filter_, device_, s, n); } |
|
321 |
|
322 template<typename Filter, typename Device, typename Mode> |
|
323 inline std::streamsize composite_device<Filter, Device, Mode>::write |
|
324 (const char_type* s, std::streamsize n) |
|
325 { return iostreams::write(filter_, device_, s, n); } |
|
326 |
|
327 template<typename Filter, typename Device, typename Mode> |
|
328 stream_offset composite_device<Filter, Device, Mode>::seek |
|
329 (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which) |
|
330 { return iostreams::seek(filter_, device_, off, way, which); } |
|
331 |
|
332 template<typename Filter, typename Device, typename Mode> |
|
333 void composite_device<Filter, Device, Mode>::close() |
|
334 { |
|
335 typedef typename mode_of<Device>::type device_mode; |
|
336 BOOST_IOS::openmode which = |
|
337 is_convertible<device_mode, input>() ? |
|
338 BOOST_IOS::in : |
|
339 BOOST_IOS::out; |
|
340 close(which); |
|
341 } |
|
342 |
|
343 template<typename Filter, typename Device, typename Mode> |
|
344 void composite_device<Filter, Device, Mode>::close(BOOST_IOS::openmode which) |
|
345 { |
|
346 bool nothrow = false; |
|
347 external_closer<value_type> close_device(device_, which, nothrow); |
|
348 external_closer<Filter, value_type> close_filter(filter_, device_, which, nothrow); |
|
349 } |
|
350 |
|
351 template<typename Filter, typename Device, typename Mode> |
|
352 bool composite_device<Filter, Device, Mode>::flush() |
|
353 { // To do: consider using RAII. |
|
354 bool r1 = iostreams::flush(filter_, device_); |
|
355 bool r2 = iostreams::flush(device_); |
|
356 return r1 && r2; |
|
357 } |
|
358 |
|
359 template<typename Filter, typename Device, typename Mode> |
|
360 std::streamsize |
|
361 composite_device<Filter, Device, Mode>::optimal_buffer_size() const |
|
362 { return iostreams::optimal_buffer_size(device_); } |
|
363 |
|
364 } // End namespace detail. |
|
365 |
|
366 } } // End namespaces iostreams, boost. |
|
367 |
|
368 #endif // #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED |