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 | #ifndef BOOST_IOSTREAMS_TEE_HPP_INCLUDED |
9 | #define BOOST_IOSTREAMS_TEE_HPP_INCLUDED |
10 | |
11 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
12 | # pragma once |
13 | #endif |
14 | |
15 | #include <boost/assert.hpp> |
16 | #include <boost/config.hpp> // BOOST_DEDUCE_TYPENAME. |
17 | #include <boost/iostreams/categories.hpp> |
18 | #include <boost/iostreams/detail/adapter/device_adapter.hpp> |
19 | #include <boost/iostreams/detail/adapter/filter_adapter.hpp> |
20 | #include <boost/iostreams/detail/call_traits.hpp> |
21 | #include <boost/iostreams/detail/execute.hpp> |
22 | #include <boost/iostreams/detail/functional.hpp> // call_close_all |
23 | #include <boost/iostreams/operations.hpp> |
24 | #include <boost/iostreams/pipeline.hpp> |
25 | #include <boost/iostreams/traits.hpp> |
26 | #include <boost/static_assert.hpp> |
27 | #include <boost/type_traits/is_convertible.hpp> |
28 | #include <boost/type_traits/is_same.hpp> |
29 | |
30 | namespace boost { namespace iostreams { |
31 | |
32 | // |
33 | // Template name: tee_filter. |
34 | // Template parameters: |
35 | // Device - A blocking Sink. |
36 | // |
37 | template<typename Device> |
38 | class tee_filter : public detail::filter_adapter<Device> { |
39 | public: |
40 | typedef typename detail::param_type<Device>::type param_type; |
41 | typedef typename char_type_of<Device>::type char_type; |
42 | struct category |
43 | : dual_use_filter_tag, |
44 | multichar_tag, |
45 | closable_tag, |
46 | flushable_tag, |
47 | localizable_tag, |
48 | optimally_buffered_tag |
49 | { }; |
50 | |
51 | BOOST_STATIC_ASSERT(is_device<Device>::value); |
52 | BOOST_STATIC_ASSERT(( |
53 | is_convertible< // Using mode_of causes failures on VC6-7.0. |
54 | BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, output |
55 | >::value |
56 | )); |
57 | |
58 | explicit tee_filter(param_type dev) |
59 | : detail::filter_adapter<Device>(dev) |
60 | { } |
61 | |
62 | template<typename Source> |
63 | std::streamsize read(Source& src, char_type* s, std::streamsize n) |
64 | { |
65 | std::streamsize result = iostreams::read(src, s, n); |
66 | if (result != -1) { |
67 | std::streamsize result2 = iostreams::write(this->component(), s, result); |
68 | (void) result2; // Suppress 'unused variable' warning. |
69 | BOOST_ASSERT(result == result2); |
70 | } |
71 | return result; |
72 | } |
73 | |
74 | template<typename Sink> |
75 | std::streamsize write(Sink& snk, const char_type* s, std::streamsize n) |
76 | { |
77 | std::streamsize result = iostreams::write(snk, s, n); |
78 | std::streamsize result2 = iostreams::write(this->component(), s, result); |
79 | (void) result2; // Suppress 'unused variable' warning. |
80 | BOOST_ASSERT(result == result2); |
81 | return result; |
82 | } |
83 | |
84 | template<typename Next> |
85 | void close(Next&, BOOST_IOS::openmode) |
86 | { |
87 | detail::close_all(this->component()); |
88 | } |
89 | |
90 | template<typename Sink> |
91 | bool flush(Sink& snk) |
92 | { |
93 | bool r1 = iostreams::flush(snk); |
94 | bool r2 = iostreams::flush(this->component()); |
95 | return r1 && r2; |
96 | } |
97 | }; |
98 | BOOST_IOSTREAMS_PIPABLE(tee_filter, 1) |
99 | |
100 | // |
101 | // Template name: tee_device. |
102 | // Template parameters: |
103 | // Device - A blocking Device. |
104 | // Sink - A blocking Sink. |
105 | // |
106 | template<typename Device, typename Sink> |
107 | class tee_device { |
108 | public: |
109 | typedef typename detail::param_type<Device>::type device_param; |
110 | typedef typename detail::param_type<Sink>::type sink_param; |
111 | typedef typename detail::value_type<Device>::type device_value; |
112 | typedef typename detail::value_type<Sink>::type sink_value; |
113 | typedef typename char_type_of<Device>::type char_type; |
114 | typedef typename |
115 | mpl::if_< |
116 | is_convertible< |
117 | BOOST_DEDUCED_TYPENAME |
118 | iostreams::category_of<Device>::type, |
119 | output |
120 | >, |
121 | output, |
122 | input |
123 | >::type mode; |
124 | BOOST_STATIC_ASSERT(is_device<Device>::value); |
125 | BOOST_STATIC_ASSERT(is_device<Sink>::value); |
126 | BOOST_STATIC_ASSERT(( |
127 | is_same< |
128 | char_type, |
129 | BOOST_DEDUCED_TYPENAME char_type_of<Sink>::type |
130 | >::value |
131 | )); |
132 | BOOST_STATIC_ASSERT(( |
133 | is_convertible< |
134 | BOOST_DEDUCED_TYPENAME iostreams::category_of<Sink>::type, |
135 | output |
136 | >::value |
137 | )); |
138 | struct category |
139 | : mode, |
140 | device_tag, |
141 | closable_tag, |
142 | flushable_tag, |
143 | localizable_tag, |
144 | optimally_buffered_tag |
145 | { }; |
146 | tee_device(device_param device, sink_param sink) |
147 | : dev_(device), sink_(sink) |
148 | { } |
149 | std::streamsize read(char_type* s, std::streamsize n) |
150 | { |
151 | BOOST_STATIC_ASSERT(( |
152 | is_convertible< |
153 | BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, input |
154 | >::value |
155 | )); |
156 | std::streamsize result1 = iostreams::read(dev_, s, n); |
157 | if (result1 != -1) { |
158 | std::streamsize result2 = iostreams::write(sink_, s, result1); |
159 | (void) result1; // Suppress 'unused variable' warning. |
160 | (void) result2; |
161 | BOOST_ASSERT(result1 == result2); |
162 | } |
163 | return result1; |
164 | } |
165 | std::streamsize write(const char_type* s, std::streamsize n) |
166 | { |
167 | BOOST_STATIC_ASSERT(( |
168 | is_convertible< |
169 | BOOST_DEDUCED_TYPENAME iostreams::category_of<Device>::type, output |
170 | >::value |
171 | )); |
172 | std::streamsize result1 = iostreams::write(dev_, s, n); |
173 | std::streamsize result2 = iostreams::write(sink_, s, n); |
174 | (void) result1; // Suppress 'unused variable' warning. |
175 | (void) result2; |
176 | BOOST_ASSERT(result1 == n && result2 == n); |
177 | return n; |
178 | } |
179 | void close() |
180 | { |
181 | detail::execute_all( detail::call_close_all(dev_), |
182 | detail::call_close_all(sink_) ); |
183 | } |
184 | bool flush() |
185 | { |
186 | bool r1 = iostreams::flush(dev_); |
187 | bool r2 = iostreams::flush(sink_); |
188 | return r1 && r2; |
189 | } |
190 | template<typename Locale> |
191 | void imbue(const Locale& loc) |
192 | { |
193 | iostreams::imbue(dev_, loc); |
194 | iostreams::imbue(sink_, loc); |
195 | } |
196 | std::streamsize optimal_buffer_size() const |
197 | { |
198 | return (std::max) ( iostreams::optimal_buffer_size(dev_), |
199 | iostreams::optimal_buffer_size(sink_) ); |
200 | } |
201 | private: |
202 | device_value dev_; |
203 | sink_value sink_; |
204 | }; |
205 | |
206 | template<typename Sink> |
207 | tee_filter<Sink> tee(Sink& snk) |
208 | { return tee_filter<Sink>(snk); } |
209 | |
210 | template<typename Sink> |
211 | tee_filter<Sink> tee(const Sink& snk) |
212 | { return tee_filter<Sink>(snk); } |
213 | |
214 | template<typename Device, typename Sink> |
215 | tee_device<Device, Sink> tee(Device& dev, Sink& sink) |
216 | { return tee_device<Device, Sink>(dev, sink); } |
217 | |
218 | template<typename Device, typename Sink> |
219 | tee_device<Device, Sink> tee(const Device& dev, Sink& sink) |
220 | { return tee_device<Device, Sink>(dev, sink); } |
221 | |
222 | template<typename Device, typename Sink> |
223 | tee_device<Device, Sink> tee(Device& dev, const Sink& sink) |
224 | { return tee_device<Device, Sink>(dev, sink); } |
225 | |
226 | template<typename Device, typename Sink> |
227 | tee_device<Device, Sink> tee(const Device& dev, const Sink& sink) |
228 | { return tee_device<Device, Sink>(dev, sink); } |
229 | |
230 | } } // End namespaces iostreams, boost. |
231 | |
232 | #endif // #ifndef BOOST_IOSTREAMS_TEE_HPP_INCLUDED |
233 | |