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