]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) |
2 | // (C) Copyright 2005-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 | // Note: bidirectional streams are not supported. | |
9 | ||
10 | #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED | |
11 | #define BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED | |
12 | ||
13 | #if defined(_MSC_VER) | |
14 | # pragma once | |
15 | #endif | |
16 | ||
17 | #include <algorithm> // min. | |
18 | #include <utility> // pair. | |
19 | #include <boost/config.hpp> // DEDUCED_TYPENAME. | |
20 | #include <boost/iostreams/categories.hpp> | |
21 | #include <boost/iostreams/detail/adapter/direct_adapter.hpp> | |
22 | #include <boost/iostreams/detail/call_traits.hpp> | |
23 | #include <boost/iostreams/detail/enable_if_stream.hpp> | |
24 | #include <boost/iostreams/detail/execute.hpp> | |
25 | #include <boost/iostreams/detail/functional.hpp> | |
26 | #include <boost/iostreams/operations.hpp> | |
27 | #include <boost/iostreams/traits.hpp> // mode_of, is_direct. | |
28 | #include <boost/mpl/if.hpp> | |
29 | #include <boost/ref.hpp> | |
30 | #include <boost/static_assert.hpp> | |
31 | #include <boost/type_traits/is_convertible.hpp> | |
32 | ||
33 | // Must come last. | |
34 | #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC. | |
35 | ||
36 | namespace boost { namespace iostreams { | |
37 | ||
38 | namespace detail { | |
39 | ||
40 | template< typename First, | |
41 | typename Second, | |
42 | typename FirstMode = | |
43 | BOOST_DEDUCED_TYPENAME mode_of<First>::type, | |
44 | typename SecondMode = | |
45 | BOOST_DEDUCED_TYPENAME mode_of<Second>::type > | |
46 | struct composite_mode | |
47 | : select< | |
48 | is_convertible<SecondMode, FirstMode>, FirstMode, | |
49 | is_convertible<FirstMode, SecondMode>, SecondMode, | |
50 | is_convertible<SecondMode, input>, input, | |
51 | else_, output | |
52 | > | |
53 | { }; | |
54 | ||
55 | // | |
56 | // Template name: composite_device. | |
57 | // Description: Provides a Device view of a Filter, Device pair. | |
58 | // Template parameters: | |
59 | // Filter - A model of Filter. | |
60 | // Device - An indirect model of Device. | |
61 | // | |
62 | template< typename Filter, | |
63 | typename Device, | |
64 | typename Mode = | |
65 | BOOST_DEDUCED_TYPENAME composite_mode<Filter, Device>::type > | |
66 | class composite_device { | |
67 | private: | |
68 | typedef typename detail::param_type<Device>::type param_type; | |
69 | typedef typename mode_of<Filter>::type filter_mode; | |
70 | typedef typename mode_of<Device>::type device_mode; | |
71 | typedef typename | |
72 | iostreams::select< // Disambiguation for Tru64. | |
73 | is_direct<Device>, direct_adapter<Device>, | |
74 | is_std_io<Device>, Device&, | |
75 | else_, Device | |
76 | >::type value_type; | |
77 | BOOST_STATIC_ASSERT(is_filter<Filter>::value); | |
78 | BOOST_STATIC_ASSERT(is_device<Device>::value); | |
79 | public: | |
80 | typedef typename char_type_of<Filter>::type char_type; | |
81 | struct category | |
82 | : Mode, | |
83 | device_tag, | |
84 | closable_tag, | |
85 | flushable_tag, | |
86 | localizable_tag, | |
87 | optimally_buffered_tag | |
88 | { }; | |
89 | composite_device(const Filter& flt, param_type dev); | |
90 | std::streamsize read(char_type* s, std::streamsize n); | |
91 | std::streamsize write(const char_type* s, std::streamsize n); | |
92 | std::streampos seek( stream_offset off, BOOST_IOS::seekdir way, | |
93 | BOOST_IOS::openmode which = | |
94 | BOOST_IOS::in | BOOST_IOS::out ); | |
95 | ||
96 | void close(); | |
97 | void close(BOOST_IOS::openmode which); | |
98 | bool flush(); | |
99 | std::streamsize optimal_buffer_size() const; | |
100 | ||
101 | template<typename Locale> // Avoid dependency on <locale> | |
102 | void imbue(const Locale& loc) | |
103 | { | |
104 | iostreams::imbue(filter_, loc); | |
105 | iostreams::imbue(device_, loc); | |
106 | } | |
107 | ||
108 | Filter& first() { return filter_; } | |
109 | Device& second() { return device_; } | |
110 | private: | |
111 | Filter filter_; | |
112 | value_type device_; | |
113 | }; | |
114 | ||
115 | // | |
116 | // Template name: composite_device. | |
117 | // Description: Provides a Device view of a Filter, Device pair. | |
118 | // Template parameters: | |
119 | // Filter - A model of Filter. | |
120 | // Device - An indirect model of Device. | |
121 | // | |
122 | template< typename Filter1, | |
123 | typename Filter2, | |
124 | typename Mode = | |
125 | BOOST_DEDUCED_TYPENAME composite_mode<Filter1, Filter2>::type > | |
126 | class composite_filter { | |
127 | private: | |
128 | typedef reference_wrapper<Filter2> filter_ref; | |
129 | typedef typename mode_of<Filter1>::type first_mode; | |
130 | typedef typename mode_of<Filter2>::type second_mode; | |
131 | ||
132 | // A dual-use filter cannot be composed with a read-write filter | |
133 | BOOST_STATIC_ASSERT( | |
134 | !(is_convertible<first_mode, dual_use>::value) || | |
135 | !(is_convertible<second_mode, input>::value) || | |
136 | !(is_convertible<second_mode, output>::value) || | |
137 | (is_convertible<second_mode, dual_use>::value) | |
138 | ); | |
139 | BOOST_STATIC_ASSERT( | |
140 | !(is_convertible<second_mode, dual_use>::value) || | |
141 | !(is_convertible<first_mode, input>::value) || | |
142 | !(is_convertible<first_mode, output>::value) || | |
143 | (is_convertible<first_mode, dual_use>::value) | |
144 | ); | |
145 | BOOST_STATIC_ASSERT(is_filter<Filter1>::value); | |
146 | BOOST_STATIC_ASSERT(is_filter<Filter2>::value); | |
147 | public: | |
148 | typedef typename char_type_of<Filter1>::type char_type; | |
149 | struct category | |
150 | : Mode, | |
151 | filter_tag, | |
152 | multichar_tag, | |
153 | closable_tag, | |
154 | flushable_tag, | |
155 | localizable_tag, | |
156 | optimally_buffered_tag | |
157 | { }; | |
158 | composite_filter(const Filter1& filter1, const Filter2& filter2) | |
159 | : filter1_(filter1), filter2_(filter2) | |
160 | { } | |
161 | ||
162 | template<typename Source> | |
163 | std::streamsize read(Source& src, char_type* s, std::streamsize n) | |
164 | { | |
165 | composite_device<filter_ref, Source> cmp(boost::ref(filter2_), src); | |
166 | return iostreams::read(filter1_, cmp, s, n); | |
167 | } | |
168 | ||
169 | template<typename Sink> | |
170 | std::streamsize write(Sink& snk, const char_type* s, std::streamsize n) | |
171 | { | |
172 | composite_device<filter_ref, Sink> cmp(boost::ref(filter2_), snk); | |
173 | return iostreams::write(filter1_, cmp, s, n); | |
174 | } | |
175 | ||
176 | template<typename Device> | |
177 | std::streampos seek( Device& dev, stream_offset off, BOOST_IOS::seekdir way, | |
178 | BOOST_IOS::openmode which = | |
179 | BOOST_IOS::in | BOOST_IOS::out ) | |
180 | { | |
181 | composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev); | |
182 | return iostreams::seek(filter1_, cmp, off, way, which); | |
183 | } | |
184 | ||
185 | template<typename Device> | |
186 | void close(Device& dev) | |
187 | { | |
188 | BOOST_STATIC_ASSERT((!is_convertible<category, two_sequence>::value)); | |
189 | BOOST_STATIC_ASSERT((!is_convertible<category, dual_use>::value)); | |
190 | ||
191 | // Create a new device by composing the second filter2_ with dev. | |
192 | composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev); | |
193 | ||
194 | // Close input sequences in reverse order and output sequences in | |
195 | // forward order | |
196 | if (!is_convertible<first_mode, dual_use>::value) { | |
197 | detail::execute_all( | |
198 | detail::call_close(filter2_, dev, BOOST_IOS::in), | |
199 | detail::call_close(filter1_, cmp, BOOST_IOS::in), | |
200 | detail::call_close(filter1_, cmp, BOOST_IOS::out), | |
201 | detail::call_close(filter2_, dev, BOOST_IOS::out) | |
202 | ); | |
203 | } else if (is_convertible<second_mode, input>::value) { | |
204 | detail::execute_all( | |
205 | detail::call_close(filter2_, dev, BOOST_IOS::in), | |
206 | detail::call_close(filter1_, cmp, BOOST_IOS::in) | |
207 | ); | |
208 | } else { | |
209 | detail::execute_all( | |
210 | detail::call_close(filter1_, cmp, BOOST_IOS::out), | |
211 | detail::call_close(filter2_, dev, BOOST_IOS::out) | |
212 | ); | |
213 | } | |
214 | } | |
215 | ||
216 | template<typename Device> | |
217 | void close(Device& dev, BOOST_IOS::openmode which) | |
218 | { | |
219 | BOOST_STATIC_ASSERT( | |
220 | (is_convertible<category, two_sequence>::value) || | |
221 | (is_convertible<category, dual_use>::value) | |
222 | ); | |
223 | ||
224 | // Create a new device by composing the second filter2_ with dev. | |
225 | composite_device<filter_ref, Device> cmp(boost::ref(filter2_), dev); | |
226 | ||
227 | // Close input sequences in reverse order | |
228 | if ( which == BOOST_IOS::in && | |
229 | ( !is_convertible<first_mode, dual_use>::value || | |
230 | is_convertible<second_mode, input>::value ) ) | |
231 | { | |
232 | detail::execute_all( | |
233 | detail::call_close(filter2_, dev, BOOST_IOS::in), | |
234 | detail::call_close(filter1_, cmp, BOOST_IOS::in) | |
235 | ); | |
236 | } | |
237 | ||
238 | // Close output sequences in forward order | |
239 | if ( which == BOOST_IOS::out && | |
240 | ( !is_convertible<first_mode, dual_use>::value || | |
241 | is_convertible<second_mode, output>::value ) ) | |
242 | { | |
243 | detail::execute_all( | |
244 | detail::call_close(filter1_, cmp, BOOST_IOS::out), | |
245 | detail::call_close(filter2_, dev, BOOST_IOS::out) | |
246 | ); | |
247 | } | |
248 | } | |
249 | ||
250 | template<typename Device> | |
251 | bool flush(Device& dev) | |
252 | { | |
253 | composite_device<Filter2, Device> cmp(filter2_, dev); | |
254 | return iostreams::flush(filter1_, cmp); | |
255 | } | |
256 | ||
257 | std::streamsize optimal_buffer_size() const | |
258 | { | |
259 | std::streamsize first = iostreams::optimal_buffer_size(filter1_); | |
260 | std::streamsize second = iostreams::optimal_buffer_size(filter2_); | |
261 | return first < second ? second : first; | |
262 | } | |
263 | ||
264 | template<typename Locale> // Avoid dependency on <locale> | |
265 | void imbue(const Locale& loc) | |
266 | { // To do: consider using RAII. | |
267 | iostreams::imbue(filter1_, loc); | |
268 | iostreams::imbue(filter2_, loc); | |
269 | } | |
270 | ||
271 | Filter1& first() { return filter1_; } | |
272 | Filter2& second() { return filter2_; } | |
273 | private: | |
274 | Filter1 filter1_; | |
275 | Filter2 filter2_; | |
276 | }; | |
277 | ||
278 | template<typename Filter, typename FilterOrDevice> | |
279 | struct composite_traits | |
280 | : mpl::if_< | |
281 | is_device<FilterOrDevice>, | |
282 | composite_device<Filter, FilterOrDevice>, | |
283 | composite_filter<Filter, FilterOrDevice> | |
284 | > | |
285 | { }; | |
286 | ||
287 | } // End namespace detail. | |
288 | ||
289 | template<typename Filter, typename FilterOrDevice> | |
290 | struct composite : detail::composite_traits<Filter, FilterOrDevice>::type { | |
291 | typedef typename detail::param_type<FilterOrDevice>::type param_type; | |
292 | typedef typename detail::composite_traits<Filter, FilterOrDevice>::type base; | |
293 | composite(const Filter& flt, param_type dev) | |
294 | : base(flt, dev) | |
295 | { } | |
296 | }; | |
297 | ||
298 | //--------------Implementation of compose-------------------------------------// | |
299 | ||
300 | // Note: The following workarounds are patterned after resolve.hpp. It has not | |
301 | // yet been confirmed that they are necessary. | |
302 | ||
303 | #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //-------------------------// | |
304 | # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //-------------------------------// | |
305 | ||
306 | template<typename Filter, typename FilterOrDevice> | |
307 | composite<Filter, FilterOrDevice> | |
308 | compose( const Filter& filter, const FilterOrDevice& fod | |
309 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) ) | |
310 | { return composite<Filter, FilterOrDevice>(filter, fod); } | |
311 | ||
312 | template<typename Filter, typename Ch, typename Tr> | |
313 | composite< Filter, std::basic_streambuf<Ch, Tr> > | |
314 | compose(const Filter& filter, std::basic_streambuf<Ch, Tr>& sb) | |
315 | { return composite< Filter, std::basic_streambuf<Ch, Tr> >(filter, sb); } | |
316 | ||
317 | template<typename Filter, typename Ch, typename Tr> | |
318 | composite< Filter, std::basic_istream<Ch, Tr> > | |
319 | compose(const Filter& filter, std::basic_istream<Ch, Tr>& is) | |
320 | { return composite< Filter, std::basic_istream<Ch, Tr> >(filter, is); } | |
321 | ||
322 | template<typename Filter, typename Ch, typename Tr> | |
323 | composite< Filter, std::basic_ostream<Ch, Tr> > | |
324 | compose(const Filter& filter, std::basic_ostream<Ch, Tr>& os) | |
325 | { return composite< Filter, std::basic_ostream<Ch, Tr> >(filter, os); } | |
326 | ||
327 | template<typename Filter, typename Ch, typename Tr> | |
328 | composite< Filter, std::basic_iostream<Ch, Tr> > | |
329 | compose(const Filter& filter, std::basic_iostream<Ch, Tr>& io) | |
330 | { return composite< Filter, std::basic_iostream<Ch, Tr> >(filter, io); } | |
331 | ||
332 | # else // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //---------------------// | |
333 | ||
334 | template<typename Filter, typename FilterOrDevice> | |
335 | composite<Filter, FilterOrDevice> | |
336 | compose( const Filter& filter, const FilterOrDevice& fod | |
337 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(FilterOrDevice) ) | |
338 | { return composite<Filter, FilterOrDevice>(filter, fod); } | |
339 | ||
340 | template<typename Filter> | |
341 | composite<Filter, std::streambuf> | |
342 | compose(const Filter& filter, std::streambuf& sb) | |
343 | { return composite<Filter, std::streambuf>(filter, sb); } | |
344 | ||
345 | template<typename Filter> | |
346 | composite<Filter, std::istream> | |
347 | compose(const Filter& filter, std::istream& is) | |
348 | { return composite<Filter, std::istream>(filter, is); } | |
349 | ||
350 | template<typename Filter> | |
351 | composite<Filter, std::ostream> | |
352 | compose(const Filter& filter, std::ostream& os) | |
353 | { return composite<Filter, std::ostream>(filter, os); } | |
354 | ||
355 | template<typename Filter> | |
356 | composite<Filter, std::iostream> | |
357 | compose(const Filter& filter, std::iostream& io) | |
358 | { return composite<Filter, std::iostream>(filter, io); } | |
359 | ||
360 | # endif // # ifndef BOOST_IOSTREAMS_NO_STREAM_TEMPLATES //--------------------// | |
361 | #else // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //----------------// | |
362 | ||
363 | template<typename Filter, typename Stream> | |
364 | composite<Filter, Stream> | |
365 | compose(const Filter& flt, const Stream& strm, mpl::true_) | |
366 | { // Bad overload resolution. | |
367 | return composite<Filter, Stream>(flt, const_cast<Stream&>(strm)); | |
368 | } | |
369 | ||
370 | template<typename Filter, typename FilterOrDevice> | |
371 | composite<Filter, FilterOrDevice> | |
372 | compose(const Filter& flt, const FilterOrDevice& fod, mpl::false_) | |
373 | { return composite<Filter, FilterOrDevice>(flt, fod); } | |
374 | ||
375 | template<typename Filter, typename FilterOrDevice> | |
376 | composite<Filter, FilterOrDevice> | |
377 | compose( const Filter& flt, const FilterOrDevice& fod | |
378 | BOOST_IOSTREAMS_DISABLE_IF_STREAM(T) ) | |
379 | { return compose(flt, fod, is_std_io<FilterOrDevice>()); } | |
380 | ||
381 | # if !BOOST_WORKAROUND(__BORLANDC__, < 0x600) && \ | |
382 | !defined(__GNUC__) // ---------------------------------------------------// | |
383 | ||
384 | template<typename Filter, typename FilterOrDevice> | |
385 | composite<Filter, FilterOrDevice> | |
386 | compose (const Filter& filter, FilterOrDevice& fod) | |
387 | { return composite<Filter, FilterOrDevice>(filter, fod); } | |
388 | ||
389 | # endif // Borland 5.x or GCC //--------------------------------// | |
390 | #endif // #ifndef BOOST_IOSTREAMS_BROKEN_OVERLOAD_RESOLUTION //---------------// | |
391 | ||
392 | //----------------------------------------------------------------------------// | |
393 | ||
394 | namespace detail { | |
395 | ||
396 | //--------------Implementation of composite_device---------------------------// | |
397 | ||
398 | template<typename Filter, typename Device, typename Mode> | |
399 | composite_device<Filter, Device, Mode>::composite_device | |
400 | (const Filter& flt, param_type dev) | |
401 | : filter_(flt), device_(dev) | |
402 | { } | |
403 | ||
404 | template<typename Filter, typename Device, typename Mode> | |
405 | inline std::streamsize composite_device<Filter, Device, Mode>::read | |
406 | (char_type* s, std::streamsize n) | |
407 | { return iostreams::read(filter_, device_, s, n); } | |
408 | ||
409 | template<typename Filter, typename Device, typename Mode> | |
410 | inline std::streamsize composite_device<Filter, Device, Mode>::write | |
411 | (const char_type* s, std::streamsize n) | |
412 | { return iostreams::write(filter_, device_, s, n); } | |
413 | ||
414 | template<typename Filter, typename Device, typename Mode> | |
415 | std::streampos composite_device<Filter, Device, Mode>::seek | |
416 | (stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode which) | |
417 | { return iostreams::seek(filter_, device_, off, way, which); } | |
418 | ||
419 | template<typename Filter, typename Device, typename Mode> | |
420 | void composite_device<Filter, Device, Mode>::close() | |
421 | { | |
422 | BOOST_STATIC_ASSERT((!is_convertible<Mode, two_sequence>::value)); | |
423 | BOOST_STATIC_ASSERT( | |
424 | !(is_convertible<filter_mode, dual_use>::value) || | |
425 | !(is_convertible<device_mode, input>::value) || | |
426 | !(is_convertible<device_mode, output>::value) | |
427 | ); | |
428 | ||
429 | // Close input sequences in reverse order and output sequences | |
430 | // in forward order | |
431 | if (!is_convertible<filter_mode, dual_use>::value) { | |
432 | detail::execute_all( | |
433 | detail::call_close(device_, BOOST_IOS::in), | |
434 | detail::call_close(filter_, device_, BOOST_IOS::in), | |
435 | detail::call_close(filter_, device_, BOOST_IOS::out), | |
436 | detail::call_close(device_, BOOST_IOS::out) | |
437 | ); | |
438 | } else if (is_convertible<device_mode, input>::value) { | |
439 | detail::execute_all( | |
440 | detail::call_close(device_, BOOST_IOS::in), | |
441 | detail::call_close(filter_, device_, BOOST_IOS::in) | |
442 | ); | |
443 | } else { | |
444 | detail::execute_all( | |
445 | detail::call_close(filter_, device_, BOOST_IOS::out), | |
446 | detail::call_close(device_, BOOST_IOS::out) | |
447 | ); | |
448 | } | |
449 | } | |
450 | ||
451 | template<typename Filter, typename Device, typename Mode> | |
452 | void composite_device<Filter, Device, Mode>::close(BOOST_IOS::openmode which) | |
453 | { | |
454 | BOOST_STATIC_ASSERT((is_convertible<Mode, two_sequence>::value)); | |
455 | BOOST_STATIC_ASSERT(!(is_convertible<filter_mode, dual_use>::value)); | |
456 | ||
457 | // Close input sequences in reverse order | |
458 | if (which == BOOST_IOS::in) { | |
459 | detail::execute_all( | |
460 | detail::call_close(device_, BOOST_IOS::in), | |
461 | detail::call_close(filter_, device_, BOOST_IOS::in) | |
462 | ); | |
463 | } | |
464 | ||
465 | // Close output sequences in forward order | |
466 | if (which == BOOST_IOS::out) { | |
467 | detail::execute_all( | |
468 | detail::call_close(filter_, device_, BOOST_IOS::out), | |
469 | detail::call_close(device_, BOOST_IOS::out) | |
470 | ); | |
471 | } | |
472 | } | |
473 | ||
474 | template<typename Filter, typename Device, typename Mode> | |
475 | bool composite_device<Filter, Device, Mode>::flush() | |
476 | { | |
477 | bool r1 = iostreams::flush(filter_, device_); | |
478 | bool r2 = iostreams::flush(device_); | |
479 | return r1 && r2; | |
480 | } | |
481 | ||
482 | template<typename Filter, typename Device, typename Mode> | |
483 | std::streamsize | |
484 | composite_device<Filter, Device, Mode>::optimal_buffer_size() const | |
485 | { return iostreams::optimal_buffer_size(device_); } | |
486 | ||
487 | } // End namespace detail. | |
488 | ||
489 | } } // End namespaces iostreams, boost. | |
490 | ||
491 | #include <boost/iostreams/detail/config/enable_warnings.hpp> | |
492 | ||
493 | #endif // #ifndef BOOST_IOSTREAMS_COMPOSE_HPP_INCLUDED |