|
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 #ifndef BOOST_IOSTREAMS_INVERT_HPP_INCLUDED |
|
8 #define BOOST_IOSTREAMS_INVERT_HPP_INCLUDED |
|
9 |
|
10 #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
|
11 # pragma once |
|
12 #endif |
|
13 |
|
14 #include <algorithm> // copy, min. |
|
15 #include <cassert> |
|
16 #include <boost/config.hpp> // BOOST_DEDUCED_TYPENAME. |
|
17 #include <boost/detail/workaround.hpp> // default_filter_buffer_size. |
|
18 #include <boost/iostreams/char_traits.hpp> |
|
19 #include <boost/iostreams/compose.hpp> |
|
20 #include <boost/iostreams/constants.hpp> |
|
21 #include <boost/iostreams/device/array.hpp> |
|
22 #include <boost/iostreams/detail/buffer.hpp> |
|
23 #include <boost/iostreams/detail/counted_array.hpp> |
|
24 #include <boost/mpl/if.hpp> |
|
25 #include <boost/ref.hpp> |
|
26 #include <boost/shared_ptr.hpp> |
|
27 #include <boost/type_traits/is_convertible.hpp> |
|
28 |
|
29 // Must come last. |
|
30 #include <boost/iostreams/detail/config/disable_warnings.hpp> // MSVC. |
|
31 |
|
32 namespace boost { namespace iostreams { |
|
33 |
|
34 // |
|
35 // Template name: inverse. |
|
36 // Template paramters: |
|
37 // Filter - A filter adapter which |
|
38 // Description: Returns an instance of an appropriate specialization of inverse. |
|
39 // |
|
40 template<typename Filter> |
|
41 class inverse { |
|
42 private: |
|
43 typedef typename category_of<Filter>::type base_category; |
|
44 typedef reference_wrapper<Filter> filter_ref; |
|
45 public: |
|
46 typedef typename char_type_of<Filter>::type char_type; |
|
47 typedef typename int_type_of<Filter>::type int_type; |
|
48 typedef char_traits<char_type> traits_type; |
|
49 typedef typename |
|
50 mpl::if_< |
|
51 is_convertible< |
|
52 base_category, |
|
53 input |
|
54 >, |
|
55 output, |
|
56 input |
|
57 >::type mode; |
|
58 struct category |
|
59 : mode, |
|
60 filter_tag, |
|
61 multichar_tag, |
|
62 closable_tag |
|
63 { }; |
|
64 explicit inverse( const Filter& filter, |
|
65 std::streamsize buffer_size = |
|
66 default_filter_buffer_size) |
|
67 : pimpl_(new impl(filter, buffer_size)) |
|
68 { } |
|
69 |
|
70 template<typename Source> |
|
71 std::streamsize read(Source& src, char* s, std::streamsize n) |
|
72 { |
|
73 typedef detail::counted_array_sink<char_type> array_sink; |
|
74 typedef composite<filter_ref, array_sink> filtered_array_sink; |
|
75 |
|
76 assert((flags() & f_write) == 0); |
|
77 if (flags() == 0) { |
|
78 flags() = f_read; |
|
79 buf().set(0, 0); |
|
80 } |
|
81 |
|
82 filtered_array_sink snk(filter(), array_sink(s, n)); |
|
83 int_type status; |
|
84 for ( status = traits_type::good(); |
|
85 snk.second().count() < n && status == traits_type::good(); ) |
|
86 { |
|
87 status = buf().fill(src); |
|
88 buf().flush(snk); |
|
89 } |
|
90 return snk.second().count() == 0 && |
|
91 status == traits_type::eof() |
|
92 ? |
|
93 -1 |
|
94 : |
|
95 snk.second().count(); |
|
96 } |
|
97 |
|
98 template<typename Sink> |
|
99 std::streamsize write(Sink& dest, const char* s, std::streamsize n) |
|
100 { |
|
101 typedef detail::counted_array_source<char_type> array_source; |
|
102 typedef composite<filter_ref, array_source> filtered_array_source; |
|
103 |
|
104 assert((flags() & f_read) == 0); |
|
105 if (flags() == 0) { |
|
106 flags() = f_write; |
|
107 buf().set(0, 0); |
|
108 } |
|
109 |
|
110 filtered_array_source src(filter(), array_source(s, n)); |
|
111 for (bool good = true; src.second().count() < n && good; ) { |
|
112 buf().fill(src); |
|
113 good = buf().flush(dest); |
|
114 } |
|
115 return src.second().count(); |
|
116 } |
|
117 |
|
118 template<typename Device> |
|
119 void close( Device& dev, |
|
120 BOOST_IOS::openmode which = |
|
121 BOOST_IOS::in | BOOST_IOS::out ) |
|
122 { |
|
123 if ((which & BOOST_IOS::out) != 0 && (flags() & f_write) != 0) |
|
124 buf().flush(dev); |
|
125 flags() = 0; |
|
126 } |
|
127 private: |
|
128 filter_ref filter() { return boost::ref(pimpl_->filter_); } |
|
129 detail::buffer<char_type>& buf() { return pimpl_->buf_; } |
|
130 int& flags() { return pimpl_->flags_; } |
|
131 |
|
132 enum flags_ { |
|
133 f_read = 1, f_write = 2 |
|
134 }; |
|
135 |
|
136 struct impl { |
|
137 impl(const Filter& filter, std::streamsize n) |
|
138 : filter_(filter), buf_(n), flags_(0) |
|
139 { buf_.set(0, 0); } |
|
140 Filter filter_; |
|
141 detail::buffer<char_type> buf_; |
|
142 int flags_; |
|
143 }; |
|
144 shared_ptr<impl> pimpl_; |
|
145 }; |
|
146 |
|
147 // |
|
148 // Template name: invert. |
|
149 // Template paramters: |
|
150 // Filter - A model of InputFilter or OutputFilter. |
|
151 // Description: Returns an instance of an appropriate specialization of inverse. |
|
152 // |
|
153 template<typename Filter> |
|
154 inverse<Filter> invert(const Filter& f) { return inverse<Filter>(f); } |
|
155 |
|
156 //----------------------------------------------------------------------------// |
|
157 |
|
158 } } // End namespaces iostreams, boost. |
|
159 |
|
160 #include <boost/iostreams/detail/config/enable_warnings.hpp> // MSVC. |
|
161 |
|
162 #endif // #ifndef BOOST_IOSTREAMS_INVERT_HPP_INCLUDED |