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)
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
tee_filter(param_type dev)58 explicit tee_filter(param_type dev)
59 : detail::filter_adapter<Device>(dev)
60 { }
61
62 template<typename Source>
read(Source & src,char_type * s,std::streamsize n)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>
write(Sink & snk,const char_type * s,std::streamsize n)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>
close(Next &,BOOST_IOS::openmode)85 void close(Next&, BOOST_IOS::openmode)
86 {
87 detail::close_all(this->component());
88 }
89
90 template<typename Sink>
flush(Sink & snk)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 { };
tee_device(device_param device,sink_param sink)146 tee_device(device_param device, sink_param sink)
147 : dev_(device), sink_(sink)
148 { }
read(char_type * s,std::streamsize n)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 }
write(const char_type * s,std::streamsize n)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 }
close()179 void close()
180 {
181 detail::execute_all( detail::call_close_all(dev_),
182 detail::call_close_all(sink_) );
183 }
flush()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>
imbue(const Locale & loc)191 void imbue(const Locale& loc)
192 {
193 iostreams::imbue(dev_, loc);
194 iostreams::imbue(sink_, loc);
195 }
optimal_buffer_size() const196 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>
tee(Sink & snk)207 tee_filter<Sink> tee(Sink& snk)
208 { return tee_filter<Sink>(snk); }
209
210 template<typename Sink>
tee(const Sink & snk)211 tee_filter<Sink> tee(const Sink& snk)
212 { return tee_filter<Sink>(snk); }
213
214 template<typename Device, typename Sink>
tee(Device & dev,Sink & 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>
tee(const Device & dev,Sink & 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>
tee(Device & dev,const Sink & 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>
tee(const Device & dev,const Sink & 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