blob: a7c3cbbe433614f08c6a04a583b65e51ebc6b75a [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001// (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 NDNBOOST_IOSTREAMS_TEE_HPP_INCLUDED
9#define NDNBOOST_IOSTREAMS_TEE_HPP_INCLUDED
10
11#if defined(_MSC_VER) && (_MSC_VER >= 1020)
12# pragma once
13#endif
14
15#include <ndnboost/assert.hpp>
16#include <ndnboost/config.hpp> // NDNBOOST_DEDUCE_TYPENAME.
17#include <ndnboost/iostreams/categories.hpp>
18#include <ndnboost/iostreams/detail/adapter/device_adapter.hpp>
19#include <ndnboost/iostreams/detail/adapter/filter_adapter.hpp>
20#include <ndnboost/iostreams/detail/call_traits.hpp>
21#include <ndnboost/iostreams/detail/execute.hpp>
22#include <ndnboost/iostreams/detail/functional.hpp> // call_close_all
23#include <ndnboost/iostreams/operations.hpp>
24#include <ndnboost/iostreams/pipeline.hpp>
25#include <ndnboost/iostreams/traits.hpp>
26#include <ndnboost/static_assert.hpp>
27#include <ndnboost/type_traits/is_convertible.hpp>
28#include <ndnboost/type_traits/is_same.hpp>
29
30namespace ndnboost { namespace iostreams {
31
32//
33// Template name: tee_filter.
34// Template parameters:
35// Device - A blocking Sink.
36//
37template<typename Device>
38class tee_filter : public detail::filter_adapter<Device> {
39public:
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 NDNBOOST_STATIC_ASSERT(is_device<Device>::value);
52 NDNBOOST_STATIC_ASSERT((
53 is_convertible< // Using mode_of causes failures on VC6-7.0.
54 NDNBOOST_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 NDNBOOST_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 NDNBOOST_ASSERT(result == result2);
81 return result;
82 }
83
84 template<typename Next>
85 void close(Next&, NDNBOOST_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};
98NDNBOOST_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//
106template<typename Device, typename Sink>
107class tee_device {
108public:
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 NDNBOOST_DEDUCED_TYPENAME
118 iostreams::category_of<Device>::type,
119 output
120 >,
121 output,
122 input
123 >::type mode;
124 NDNBOOST_STATIC_ASSERT(is_device<Device>::value);
125 NDNBOOST_STATIC_ASSERT(is_device<Sink>::value);
126 NDNBOOST_STATIC_ASSERT((
127 is_same<
128 char_type,
129 NDNBOOST_DEDUCED_TYPENAME char_type_of<Sink>::type
130 >::value
131 ));
132 NDNBOOST_STATIC_ASSERT((
133 is_convertible<
134 NDNBOOST_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 NDNBOOST_STATIC_ASSERT((
152 is_convertible<
153 NDNBOOST_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 NDNBOOST_ASSERT(result1 == result2);
162 }
163 return result1;
164 }
165 std::streamsize write(const char_type* s, std::streamsize n)
166 {
167 NDNBOOST_STATIC_ASSERT((
168 is_convertible<
169 NDNBOOST_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 NDNBOOST_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 }
201private:
202 device_value dev_;
203 sink_value sink_;
204};
205
206template<typename Sink>
207tee_filter<Sink> tee(Sink& snk)
208{ return tee_filter<Sink>(snk); }
209
210template<typename Sink>
211tee_filter<Sink> tee(const Sink& snk)
212{ return tee_filter<Sink>(snk); }
213
214template<typename Device, typename Sink>
215tee_device<Device, Sink> tee(Device& dev, Sink& sink)
216{ return tee_device<Device, Sink>(dev, sink); }
217
218template<typename Device, typename Sink>
219tee_device<Device, Sink> tee(const Device& dev, Sink& sink)
220{ return tee_device<Device, Sink>(dev, sink); }
221
222template<typename Device, typename Sink>
223tee_device<Device, Sink> tee(Device& dev, const Sink& sink)
224{ return tee_device<Device, Sink>(dev, sink); }
225
226template<typename Device, typename Sink>
227tee_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 NDNBOOST_IOSTREAMS_TEE_HPP_INCLUDED