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) && (_MSC_VER >= 1020)
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 #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) //-----------------------------------//
81 # include <boost/iostreams/detail/vc6/close.hpp>
82 #else // #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) //--------------------------//
83 
84 namespace boost { namespace iostreams {
85 
86 namespace detail {
87 
88 template<typename T>
89 struct close_impl;
90 
91 } // End namespace detail.
92 
93 template<typename T>
close(T & t)94 void close(T& t) { detail::close_all(t); }
95 
96 template<typename T>
close(T & t,BOOST_IOS::openmode which)97 void close(T& t, BOOST_IOS::openmode which)
98 {
99 #ifdef BOOST_IOSTREAMS_STRICT
100     BOOST_ASSERT(which == BOOST_IOS::in || which == BOOST_IOS::out);
101 #else
102     if (which == (BOOST_IOS::in | BOOST_IOS::out)) {
103         detail::close_all(t);
104         return;
105     }
106 #endif
107     detail::close_impl<T>::close(detail::unwrap(t), which);
108 }
109 
110 template<typename T, typename Sink>
close(T & t,Sink & snk,BOOST_IOS::openmode which)111 void close(T& t, Sink& snk, BOOST_IOS::openmode which)
112 {
113 #ifdef BOOST_IOSTREAMS_STRICT
114     BOOST_ASSERT(which == BOOST_IOS::in || which == BOOST_IOS::out);
115 #else
116     if (which == (BOOST_IOS::in | BOOST_IOS::out)) {
117         detail::close_all(t, snk);
118         return;
119     }
120 #endif
121     detail::close_impl<T>::close(detail::unwrap(t), snk, which);
122 }
123 
124 namespace detail {
125 
126 //------------------Definition of close_impl----------------------------------//
127 
128 struct close_boost_stream { };
129 struct close_filtering_stream { };
130 
131 template<typename T>
132 struct close_tag {
133     typedef typename category_of<T>::type             category;
134     typedef typename detail::unwrapped_type<T>::type  unwrapped;
135     typedef typename
136             iostreams::select<
137                 mpl::not_< is_convertible<category, closable_tag> >,
138                 any_tag,
139                 mpl::or_<
140                     is_boost_stream<unwrapped>,
141                     is_boost_stream_buffer<unwrapped>
142                 >,
143                 close_boost_stream,
144                 mpl::or_<
145                     is_filtering_stream<unwrapped>,
146                     is_filtering_streambuf<unwrapped>
147                 >,
148                 close_filtering_stream,
149                 mpl::or_<
150                     is_convertible<category, two_sequence>,
151                     is_convertible<category, dual_use>
152                 >,
153                 two_sequence,
154                 else_,
155                 closable_tag
156             >::type type;
157 };
158 
159 template<typename T>
160 struct close_impl
161     : mpl::if_<
162           is_custom<T>,
163           operations<T>,
164           close_impl<BOOST_DEDUCED_TYPENAME close_tag<T>::type>
165       >::type
166     { };
167 
168 template<>
169 struct close_impl<any_tag> {
170     template<typename T>
closeboost::iostreams::detail::close_impl171     static void close(T& t, BOOST_IOS::openmode which)
172     {
173         if (which == BOOST_IOS::out)
174             iostreams::flush(t);
175     }
176 
177     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl178     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
179     {
180         if (which == BOOST_IOS::out) {
181             non_blocking_adapter<Sink> nb(snk);
182             iostreams::flush(t, nb);
183         }
184     }
185 };
186 
187 template<>
188 struct close_impl<close_boost_stream> {
189     template<typename T>
closeboost::iostreams::detail::close_impl190     static void close(T& t)
191     {
192         t.close();
193     }
194     template<typename T>
closeboost::iostreams::detail::close_impl195     static void close(T& t, BOOST_IOS::openmode which)
196     {
197         if (which == BOOST_IOS::out)
198             t.close();
199     }
200 };
201 
202 template<>
203 struct close_impl<close_filtering_stream> {
204     template<typename T>
closeboost::iostreams::detail::close_impl205     static void close(T& t, BOOST_IOS::openmode which)
206     {
207         typedef typename category_of<T>::type category;
208         const bool in =  is_convertible<category, input>::value &&
209                         !is_convertible<category, output>::value;
210         if (in == (which == BOOST_IOS::in) && t.is_complete())
211             t.pop();
212     }
213 };
214 
215 template<>
216 struct close_impl<closable_tag> {
217     template<typename T>
closeboost::iostreams::detail::close_impl218     static void close(T& t, BOOST_IOS::openmode which)
219     {
220         typedef typename category_of<T>::type category;
221         const bool in =  is_convertible<category, input>::value &&
222                         !is_convertible<category, output>::value;
223         if (in == (which == BOOST_IOS::in))
224             t.close();
225     }
226     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl227     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
228     {
229         typedef typename category_of<T>::type category;
230         const bool in =  is_convertible<category, input>::value &&
231                         !is_convertible<category, output>::value;
232         if (in == (which == BOOST_IOS::in)) {
233             non_blocking_adapter<Sink> nb(snk);
234             t.close(nb);
235         }
236     }
237 };
238 
239 template<>
240 struct close_impl<two_sequence> {
241     template<typename T>
closeboost::iostreams::detail::close_impl242     static void close(T& t, BOOST_IOS::openmode which) { t.close(which); }
243     template<typename T, typename Sink>
closeboost::iostreams::detail::close_impl244     static void close(T& t, Sink& snk, BOOST_IOS::openmode which)
245     {
246         non_blocking_adapter<Sink> nb(snk);
247         t.close(nb, which);
248     }
249 };
250 
251 } // End namespace detail.
252 
253 } } // End namespaces iostreams, boost.
254 
255 #endif // #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) //-------------------------//
256 
257 #include <boost/iostreams/detail/config/enable_warnings.hpp>
258 
259 #endif // #ifndef BOOST_IOSTREAMS_CLOSE_HPP_INCLUDED
260