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 #ifndef BOOST_IOSTREAMS_CLOSE_HPP_INCLUDED
9 #define BOOST_IOSTREAMS_CLOSE_HPP_INCLUDED
10 
11 #if defined(_MSC_VER)
12 # pragma once
13 #endif
14 
15 #include <boost/config.hpp>  // DEDUCED_TYPENAME, MSVC.
16 #include <boost/detail/workaround.hpp>
17 #include <boost/iostreams/categories.hpp>
18 #include <boost/iostreams/flush.hpp>
19 #include <boost/iostreams/detail/adapter/non_blocking_adapter.hpp>
20 #include <boost/iostreams/detail/ios.hpp> // BOOST_IOS
21 #include <boost/iostreams/detail/select.hpp>
22 #include <boost/iostreams/detail/wrap_unwrap.hpp>
23 #include <boost/iostreams/operations_fwd.hpp>
24 #include <boost/iostreams/traits.hpp>
25 #include <boost/mpl/identity.hpp>
26 #include <boost/mpl/if.hpp>
27 #include <boost/type_traits/is_convertible.hpp>
28 #include <boost/type_traits/is_integral.hpp>
29 #include <boost/type_traits/remove_cv.hpp>
30 #include <boost/type_traits/remove_reference.hpp>
31 
32 // Must come last.
33 #include <boost/iostreams/detail/config/disable_warnings.hpp>
34 
35 namespace boost { namespace iostreams {
36 
37 template<typename T>
38 void close(T& t);
39 
40 template<typename T>
41 void close(T& t, BOOST_IOS::openmode which);
42 
43 template<typename T, typename Sink>
44 void close(T& t, Sink& snk, BOOST_IOS::openmode which);
45 
46 namespace detail {
47 
48 template<typename T>
close_all(T & t)49 void close_all(T& t)
50 {
51     try {
52         boost::iostreams::close(t, BOOST_IOS::in);
53     } catch (...) {
54         try {
55             boost::iostreams::close(t, BOOST_IOS::out);
56         } catch (...) { }
57         throw;
58     }
59     boost::iostreams::close(t, BOOST_IOS::out);
60 }
61 
62 template<typename T, typename Sink>
close_all(T & t,Sink & snk)63 void close_all(T& t, Sink& snk)
64 {
65     try {
66         boost::iostreams::close(t, snk, BOOST_IOS::in);
67     } catch (...) {
68         try {
69             boost::iostreams::close(t, snk, BOOST_IOS::out);
70         } catch (...) { }
71         throw;
72     }
73     boost::iostreams::close(t, snk, BOOST_IOS::out);
74 }
75 
76 } // End namespace detail.
77 
78 } } // End namespaces iostreams, boost.
79 
80 namespace boost { namespace iostreams {
81 
82 namespace detail {
83 
84 template<typename T>
85 struct close_impl;
86 
87 } // End namespace detail.
88 
89 template<typename T>
close(T & t)90 void close(T& t) { detail::close_all(t); }
91 
92 template<typename T>
close(T & t,BOOST_IOS::openmode which)93 void close(T& t, BOOST_IOS::openmode which)
94 {
95 #ifdef BOOST_IOSTREAMS_STRICT
96     BOOST_ASSERT(which == BOOST_IOS::in || which == BOOST_IOS::out);
97 #else
98     if (which == (BOOST_IOS::in | BOOST_IOS::out)) {
99         detail::close_all(t);
100         return;
101     }
102 #endif
103     detail::close_impl<T>::close(detail::unwrap(t), which);
104 }
105 
106 template<typename T, typename Sink>
close(T & t,Sink & snk,BOOST_IOS::openmode which)107 void close(T& t, Sink& snk, BOOST_IOS::openmode which)
108 {
109 #ifdef BOOST_IOSTREAMS_STRICT
110     BOOST_ASSERT(which == BOOST_IOS::in || which == BOOST_IOS::out);
111 #else
112     if (which == (BOOST_IOS::in | BOOST_IOS::out)) {
113         detail::close_all(t, snk);
114         return;
115     }
116 #endif
117     detail::close_impl<T>::close(detail::unwrap(t), snk, which);
118 }
119 
120 namespace detail {
121 
122 //------------------Definition of close_impl----------------------------------//
123 
124 struct close_boost_stream { };
125 struct close_filtering_stream { };
126 
127 template<typename T>
128 struct close_tag {
129     typedef typename category_of<T>::type             category;
130     typedef typename detail::unwrapped_type<T>::type  unwrapped;
131     typedef typename
132             iostreams::select<
133                 mpl::not_< is_convertible<category, closable_tag> >,
134                 any_tag,
135                 mpl::or_<
136                     is_boost_stream<unwrapped>,
137                     is_boost_stream_buffer<unwrapped>
138                 >,
139                 close_boost_stream,
140                 mpl::or_<
141                     is_filtering_stream<unwrapped>,
142                     is_filtering_streambuf<unwrapped>
143                 >,
144                 close_filtering_stream,
145                 mpl::or_<
146                     is_convertible<category, two_sequence>,
147                     is_convertible<category, dual_use>
148                 >,
149                 two_sequence,
150                 else_,
151                 closable_tag
152             >::type type;
153 };
154 
155 template<typename T>
156 struct close_impl
157     : mpl::if_<
158           is_custom<T>,
159           operations<T>,
160           close_impl<BOOST_DEDUCED_TYPENAME close_tag<T>::type>
161       >::type
162     { };
163 
164 template<>
165 struct close_impl<any_tag> {
166     template<typename T>
closeboost::iostreams::detail::close_impl167     static void close(T& t, BOOST_IOS::openmode which)
168     {
169         if (which == BOOST_IOS::out)
170             iostreams::flush(t);
171     }
172 
173     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl174     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
175     {
176         if (which == BOOST_IOS::out) {
177             non_blocking_adapter<Sink> nb(snk);
178             iostreams::flush(t, nb);
179         }
180     }
181 };
182 
183 template<>
184 struct close_impl<close_boost_stream> {
185     template<typename T>
closeboost::iostreams::detail::close_impl186     static void close(T& t)
187     {
188         t.close();
189     }
190     template<typename T>
closeboost::iostreams::detail::close_impl191     static void close(T& t, BOOST_IOS::openmode which)
192     {
193         if (which == BOOST_IOS::out)
194             t.close();
195     }
196 };
197 
198 template<>
199 struct close_impl<close_filtering_stream> {
200     template<typename T>
closeboost::iostreams::detail::close_impl201     static void close(T& t, BOOST_IOS::openmode which)
202     {
203         typedef typename category_of<T>::type category;
204         const bool in =  is_convertible<category, input>::value &&
205                         !is_convertible<category, output>::value;
206         if (in == (which == BOOST_IOS::in) && t.is_complete())
207             t.pop();
208     }
209 };
210 
211 template<>
212 struct close_impl<closable_tag> {
213     template<typename T>
closeboost::iostreams::detail::close_impl214     static void close(T& t, BOOST_IOS::openmode which)
215     {
216         typedef typename category_of<T>::type category;
217         const bool in =  is_convertible<category, input>::value &&
218                         !is_convertible<category, output>::value;
219         if (in == (which == BOOST_IOS::in))
220             t.close();
221     }
222     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl223     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
224     {
225         typedef typename category_of<T>::type category;
226         const bool in =  is_convertible<category, input>::value &&
227                         !is_convertible<category, output>::value;
228         if (in == (which == BOOST_IOS::in)) {
229             non_blocking_adapter<Sink> nb(snk);
230             t.close(nb);
231         }
232     }
233 };
234 
235 template<>
236 struct close_impl<two_sequence> {
237     template<typename T>
closeboost::iostreams::detail::close_impl238     static void close(T& t, BOOST_IOS::openmode which) { t.close(which); }
239     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl240     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
241     {
242         non_blocking_adapter<Sink> nb(snk);
243         t.close(nb, which);
244     }
245 };
246 
247 } // End namespace detail.
248 
249 } } // End namespaces iostreams, boost.
250 
251 #include <boost/iostreams/detail/config/enable_warnings.hpp>
252 
253 #endif // #ifndef BOOST_IOSTREAMS_CLOSE_HPP_INCLUDED
254