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