1 // (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)
2 // (C) Copyright 2003-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 // To do: add support for random-access.
9
10 #ifndef BOOST_IOSTREAMS_COMBINE_HPP_INCLUDED
11 #define BOOST_IOSTREAMS_COMBINE_HPP_INCLUDED
12
13 #if defined(_MSC_VER)
14 # pragma once
15 #endif
16
17 #include <boost/config.hpp> // NO_STD_LOCALE, DEDUCED_TYPENAME.
18 #ifndef BOOST_NO_STD_LOCALE
19 # include <locale>
20 #endif
21 #include <boost/iostreams/detail/ios.hpp>
22 #include <boost/iostreams/detail/wrap_unwrap.hpp>
23 #include <boost/iostreams/traits.hpp>
24 #include <boost/iostreams/operations.hpp>
25 #include <boost/mpl/if.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 // Must come last.
31 #include <boost/iostreams/detail/config/disable_warnings.hpp>
32
33 namespace boost { namespace iostreams {
34
35 namespace detail {
36
37 //
38 // Template name: combined_device.
39 // Description: Model of Device defined in terms of a Source/Sink pair.
40 // Template parameters:
41 // Source - A model of Source, with the same char_type and traits_type
42 // as Sink.
43 // Sink - A model of Sink, with the same char_type and traits_type
44 // as Source.
45 //
46 template<typename Source, typename Sink>
47 class combined_device {
48 private:
49 typedef typename category_of<Source>::type in_category;
50 typedef typename category_of<Sink>::type out_category;
51 typedef typename char_type_of<Sink>::type sink_char_type;
52 public:
53 typedef typename char_type_of<Source>::type char_type;
54 struct category
55 : bidirectional,
56 device_tag,
57 closable_tag,
58 localizable_tag
59 { };
60 BOOST_STATIC_ASSERT(is_device<Source>::value);
61 BOOST_STATIC_ASSERT(is_device<Sink>::value);
62 BOOST_STATIC_ASSERT((is_convertible<in_category, input>::value));
63 BOOST_STATIC_ASSERT((is_convertible<out_category, output>::value));
64 BOOST_STATIC_ASSERT((is_same<char_type, sink_char_type>::value));
65 combined_device(const Source& src, const Sink& snk);
66 std::streamsize read(char_type* s, std::streamsize n);
67 std::streamsize write(const char_type* s, std::streamsize n);
68 void close(BOOST_IOS::openmode);
69 #ifndef BOOST_NO_STD_LOCALE
70 void imbue(const std::locale& loc);
71 #endif
72 private:
73 Source src_;
74 Sink sink_;
75 };
76
77 //
78 // Template name: combined_filter.
79 // Description: Model of Device defined in terms of a Source/Sink pair.
80 // Template parameters:
81 // InputFilter - A model of InputFilter, with the same char_type as
82 // OutputFilter.
83 // OutputFilter - A model of OutputFilter, with the same char_type as
84 // InputFilter.
85 //
86 template<typename InputFilter, typename OutputFilter>
87 class combined_filter {
88 private:
89 typedef typename category_of<InputFilter>::type in_category;
90 typedef typename category_of<OutputFilter>::type out_category;
91 typedef typename char_type_of<OutputFilter>::type output_char_type;
92 public:
93 typedef typename char_type_of<InputFilter>::type char_type;
94 struct category
95 : multichar_bidirectional_filter_tag,
96 closable_tag,
97 localizable_tag
98 { };
99 BOOST_STATIC_ASSERT(is_filter<InputFilter>::value);
100 BOOST_STATIC_ASSERT(is_filter<OutputFilter>::value);
101 BOOST_STATIC_ASSERT((is_convertible<in_category, input>::value));
102 BOOST_STATIC_ASSERT((is_convertible<out_category, output>::value));
103 BOOST_STATIC_ASSERT((is_same<char_type, output_char_type>::value));
104 combined_filter(const InputFilter& in, const OutputFilter& out);
105
106 template<typename Source>
read(Source & src,char_type * s,std::streamsize n)107 std::streamsize read(Source& src, char_type* s, std::streamsize n)
108 { return boost::iostreams::read(in_, src, s, n); }
109
110 template<typename Sink>
write(Sink & snk,const char_type * s,std::streamsize n)111 std::streamsize write(Sink& snk, const char_type* s, std::streamsize n)
112 { return boost::iostreams::write(out_, snk, s, n); }
113
114 template<typename Sink>
close(Sink & snk,BOOST_IOS::openmode which)115 void close(Sink& snk, BOOST_IOS::openmode which)
116 {
117 if (which == BOOST_IOS::in) {
118 if (is_convertible<in_category, dual_use>::value) {
119 iostreams::close(in_, snk, BOOST_IOS::in);
120 } else {
121 detail::close_all(in_, snk);
122 }
123 }
124 if (which == BOOST_IOS::out) {
125 if (is_convertible<out_category, dual_use>::value) {
126 iostreams::close(out_, snk, BOOST_IOS::out);
127 } else {
128 detail::close_all(out_, snk);
129 }
130 }
131 }
132 #ifndef BOOST_NO_STD_LOCALE
133 void imbue(const std::locale& loc);
134 #endif
135 private:
136 InputFilter in_;
137 OutputFilter out_;
138 };
139
140 template<typename In, typename Out>
141 struct combination_traits
142 : mpl::if_<
143 is_device<In>,
144 combined_device<
145 typename wrapped_type<In>::type,
146 typename wrapped_type<Out>::type
147 >,
148 combined_filter<
149 typename wrapped_type<In>::type,
150 typename wrapped_type<Out>::type
151 >
152 >
153 { };
154
155 } // End namespace detail.
156
157 template<typename In, typename Out>
158 struct combination : detail::combination_traits<In, Out>::type {
159 typedef typename detail::combination_traits<In, Out>::type base_type;
160 typedef typename detail::wrapped_type<In>::type in_type;
161 typedef typename detail::wrapped_type<Out>::type out_type;
combinationboost::iostreams::combination162 combination(const in_type& in, const out_type& out)
163 : base_type(in, out) { }
164 };
165
166 namespace detail {
167
168 // Workaround for VC6 ETI bug.
169 template<typename In, typename Out>
170 struct combine_traits {
171 typedef combination<
172 BOOST_DEDUCED_TYPENAME detail::unwrapped_type<In>::type,
173 BOOST_DEDUCED_TYPENAME detail::unwrapped_type<Out>::type
174 > type;
175 };
176
177 } // End namespace detail.
178
179 //
180 // Template name: combine.
181 // Description: Takes a Source/Sink pair or InputFilter/OutputFilter pair and
182 // returns a Source or Filter which performs input using the first member
183 // of the pair and output using the second member of the pair.
184 // Template parameters:
185 // In - A model of Source or InputFilter, with the same char_type as Out.
186 // Out - A model of Sink or OutputFilter, with the same char_type as In.
187 //
188 template<typename In, typename Out>
189 typename detail::combine_traits<In, Out>::type
combine(const In & in,const Out & out)190 combine(const In& in, const Out& out)
191 {
192 typedef typename detail::combine_traits<In, Out>::type return_type;
193 return return_type(in, out);
194 }
195
196 //----------------------------------------------------------------------------//
197
198 namespace detail {
199
200 //--------------Implementation of combined_device-----------------------------//
201
202 template<typename Source, typename Sink>
combined_device(const Source & src,const Sink & snk)203 inline combined_device<Source, Sink>::combined_device
204 (const Source& src, const Sink& snk)
205 : src_(src), sink_(snk) { }
206
207 template<typename Source, typename Sink>
208 inline std::streamsize
read(char_type * s,std::streamsize n)209 combined_device<Source, Sink>::read(char_type* s, std::streamsize n)
210 { return iostreams::read(src_, s, n); }
211
212 template<typename Source, typename Sink>
213 inline std::streamsize
write(const char_type * s,std::streamsize n)214 combined_device<Source, Sink>::write(const char_type* s, std::streamsize n)
215 { return iostreams::write(sink_, s, n); }
216
217 template<typename Source, typename Sink>
218 inline void
close(BOOST_IOS::openmode which)219 combined_device<Source, Sink>::close(BOOST_IOS::openmode which)
220 {
221 if (which == BOOST_IOS::in)
222 detail::close_all(src_);
223 if (which == BOOST_IOS::out)
224 detail::close_all(sink_);
225 }
226
227 #ifndef BOOST_NO_STD_LOCALE
228 template<typename Source, typename Sink>
imbue(const std::locale & loc)229 void combined_device<Source, Sink>::imbue(const std::locale& loc)
230 {
231 iostreams::imbue(src_, loc);
232 iostreams::imbue(sink_, loc);
233 }
234 #endif
235
236 //--------------Implementation of filter_pair---------------------------------//
237
238 template<typename InputFilter, typename OutputFilter>
combined_filter(const InputFilter & in,const OutputFilter & out)239 inline combined_filter<InputFilter, OutputFilter>::combined_filter
240 (const InputFilter& in, const OutputFilter& out) : in_(in), out_(out)
241 { }
242
243 #ifndef BOOST_NO_STD_LOCALE
244 template<typename InputFilter, typename OutputFilter>
imbue(const std::locale & loc)245 void combined_filter<InputFilter, OutputFilter>::imbue
246 (const std::locale& loc)
247 {
248 iostreams::imbue(in_, loc);
249 iostreams::imbue(out_, loc);
250 }
251 #endif
252
253
254 } // End namespace detail.
255
256 } } // End namespaces iostreams, boost.
257
258 #include <boost/iostreams/detail/config/enable_warnings.hpp>
259
260 #endif // #ifndef BOOST_IOSTREAMS_COMBINE_HPP_INCLUDED
261