1 // Copyright Alexander Nasonov 2006-2009
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef FILE_boost_scope_exit_hpp_INCLUDED
8 #define FILE_boost_scope_exit_hpp_INCLUDED
9
10 #include <boost/config.hpp>
11
12 #include <boost/detail/workaround.hpp>
13 #include <boost/preprocessor/cat.hpp>
14 #include <boost/preprocessor/facilities/empty.hpp>
15 #include <boost/preprocessor/punctuation/comma_if.hpp>
16 #include <boost/preprocessor/seq/cat.hpp>
17 #include <boost/preprocessor/seq/for_each_i.hpp>
18 #include <boost/preprocessor/tuple/elem.hpp>
19 #include <boost/typeof/typeof.hpp>
20
21 #if defined(__GNUC__) && !defined(BOOST_INTEL)
22 # define BOOST_SCOPE_EXIT_AUX_GCC (__GNUC__ * 100 + __GNUC_MINOR__)
23 #else
24 # define BOOST_SCOPE_EXIT_AUX_GCC 0
25 #endif
26
27 #if BOOST_WORKAROUND(BOOST_SCOPE_EXIT_AUX_GCC, BOOST_TESTED_AT(413))
28 #define BOOST_SCOPE_EXIT_AUX_TPL_WORKAROUND
29 #endif
30
31 // Steven Watanabe's trick with a modification suggested by Kim Barrett
32 namespace boost { namespace scope_exit { namespace aux {
33
34 // Type of a local boost_scope_exit_args variable.
35 // First use in a local scope will declare the boost_scope_exit_args
36 // variable, subsequent uses will be resolved as two comparisons
37 // (cmp1 with 0 and cmp2 with boost_scope_exit_args).
38 template<int Dummy = 0>
39 struct declared
40 {
41 void* value;
42 static int const cmp2 = 0;
operator >(int,declared const &)43 friend void operator>(int, declared const&) {}
44 };
45
46 struct undeclared { declared<> dummy[2]; };
47
48 template<int> struct resolve;
49
50 template<>
51 struct resolve<sizeof(declared<>)>
52 {
53 static const int cmp1 = 0;
54 };
55
56 template<>
57 struct resolve<sizeof(undeclared)>
58 {
59 template<int>
60 struct cmp1
61 {
62 static int const cmp2 = 0;
63 };
64 };
65 } } }
66
67 extern boost::scope_exit::aux::undeclared boost_scope_exit_args; // undefined
68
69
70 namespace boost { namespace scope_exit { namespace aux {
71
72 typedef void (*ref_tag)(int&);
73 typedef void (*val_tag)(int );
74
75 template<class T, class Tag> struct member;
76
77 template<class T>
78 struct member<T,ref_tag>
79 {
80 T& value;
81 #ifndef BOOST_SCOPE_EXIT_AUX_TPL_WORKAROUND
memberboost::scope_exit::aux::member82 member(T& ref) : value(ref) {}
83 #endif
84 };
85
86 template<class T>
87 struct member<T,val_tag>
88 {
89 T value;
90 #ifndef BOOST_SCOPE_EXIT_AUX_TPL_WORKAROUND
memberboost::scope_exit::aux::member91 member(T& val) : value(val) {}
92 #endif
93 };
94
deref(T * p,ref_tag)95 template<class T> inline T& deref(T* p, ref_tag) { return *p; }
deref(T & r,val_tag)96 template<class T> inline T& deref(T& r, val_tag) { return r; }
97
98 template<class T>
99 struct wrapper
100 {
101 typedef T type;
102 };
103
104 template<class T> wrapper<T> wrap(T&);
105
106 } } }
107
108 #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
109 BOOST_TYPEOF_REGISTER_TEMPLATE(boost::scope_exit::aux::wrapper, 1)
110
111 #define BOOST_SCOPE_EXIT_AUX_GUARD(id) BOOST_PP_CAT(boost_se_guard_, id)
112 #define BOOST_SCOPE_EXIT_AUX_GUARD_T(id) BOOST_PP_CAT(boost_se_guard_t_, id)
113 #define BOOST_SCOPE_EXIT_AUX_PARAMS(id) BOOST_PP_CAT(boost_se_params_, id)
114 #define BOOST_SCOPE_EXIT_AUX_PARAMS_T(id) BOOST_PP_CAT(boost_se_params_t_, id)
115
116 #define BOOST_SCOPE_EXIT_AUX_TAG(id, i) \
117 BOOST_PP_SEQ_CAT( (boost_se_tag_)(i)(_)(id) )
118
119 #define BOOST_SCOPE_EXIT_AUX_PARAM(id, i, var) \
120 BOOST_PP_SEQ_CAT( (boost_se_param_)(i)(_)(id) )
121
122 #define BOOST_SCOPE_EXIT_AUX_PARAM_T(id, i, var) \
123 BOOST_PP_SEQ_CAT( (boost_se_param_t_)(i)(_)(id) )
124
125 #define BOOST_SCOPE_EXIT_AUX_CAPTURE_T(id, i, var) \
126 BOOST_PP_SEQ_CAT( (boost_se_capture_t_)(i)(_)(id) )
127
128 #define BOOST_SCOPE_EXIT_AUX_WRAPPED(id, i) \
129 BOOST_PP_SEQ_CAT( (boost_se_wrapped_t_)(i)(_)(id) )
130
131 #define BOOST_SCOPE_EXIT_AUX_DEREF(id, i, var) \
132 boost::scope_exit::aux::deref(var, (BOOST_SCOPE_EXIT_AUX_TAG(id,i))0)
133
134 #define BOOST_SCOPE_EXIT_AUX_MEMBER(r, id, i, var) \
135 boost::scope_exit::aux::member< \
136 BOOST_SCOPE_EXIT_AUX_PARAM_T(id,i,var), \
137 BOOST_SCOPE_EXIT_AUX_TAG(id,i) \
138 > BOOST_SCOPE_EXIT_AUX_PARAM(id,i,var);
139
140 // idty is (id,typename) or (id,BOOST_PP_EMPTY())
141 #define BOOST_SCOPE_EXIT_AUX_ARG_DECL(r, idty, i, var) \
142 BOOST_PP_COMMA_IF(i) BOOST_PP_TUPLE_ELEM(2,1,idty) \
143 BOOST_SCOPE_EXIT_AUX_PARAMS_T(BOOST_PP_TUPLE_ELEM(2,0,idty)):: \
144 BOOST_SCOPE_EXIT_AUX_PARAM_T(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var) var
145
146 #define BOOST_SCOPE_EXIT_AUX_ARG(r, id, i, var) BOOST_PP_COMMA_IF(i) \
147 boost_se_params_->BOOST_SCOPE_EXIT_AUX_PARAM(id,i,var).value
148
149 #define BOOST_SCOPE_EXIT_AUX_TAG_DECL(r, id, i, var) \
150 typedef void (*BOOST_SCOPE_EXIT_AUX_TAG(id,i))(int var);
151
152
153 #ifdef BOOST_SCOPE_EXIT_AUX_TPL_WORKAROUND
154
155 #define BOOST_SCOPE_EXIT_AUX_PARAMS_T_CTOR(id, seq)
156
157 #define BOOST_SCOPE_EXIT_AUX_PARAM_INIT(r, id, i, var) \
158 BOOST_PP_COMMA_IF(i) { BOOST_SCOPE_EXIT_AUX_DEREF(id,i,var) }
159
160 #define BOOST_SCOPE_EXIT_AUX_PARAMS_INIT(id, seq) \
161 = { BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_PARAM_INIT, id, seq) };
162
163 #else
164
165 #define BOOST_SCOPE_EXIT_AUX_CTOR_ARG(r, id, i, var) BOOST_PP_COMMA_IF(i) \
166 BOOST_SCOPE_EXIT_AUX_PARAM_T(id,i,var) & BOOST_PP_CAT(a,i)
167
168 #define BOOST_SCOPE_EXIT_AUX_MEMBER_INIT(r, id, i, var) BOOST_PP_COMMA_IF(i) \
169 BOOST_SCOPE_EXIT_AUX_PARAM(id,i,var) ( BOOST_PP_CAT(a,i) )
170
171 #define BOOST_SCOPE_EXIT_AUX_PARAMS_T_CTOR(id, seq) \
172 BOOST_SCOPE_EXIT_AUX_PARAMS_T(id)( \
173 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_CTOR_ARG, id, seq ) ) \
174 : BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_MEMBER_INIT, id, seq) {}
175
176 #define BOOST_SCOPE_EXIT_AUX_PARAM_INIT(r, id, i, var) \
177 BOOST_PP_COMMA_IF(i) BOOST_SCOPE_EXIT_AUX_DEREF(id,i,var)
178
179 #define BOOST_SCOPE_EXIT_AUX_PARAMS_INIT(id, seq) \
180 ( BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_PARAM_INIT, id, seq) );
181
182 #endif
183
184 #if defined(BOOST_TYPEOF_EMULATION)
185
186 #define BOOST_SCOPE_EXIT_AUX_CAPTURE_DECL(r, idty, i, var) \
187 struct BOOST_SCOPE_EXIT_AUX_WRAPPED(BOOST_PP_TUPLE_ELEM(2,0,idty), i) \
188 : BOOST_TYPEOF(boost::scope_exit::aux::wrap( \
189 BOOST_SCOPE_EXIT_AUX_DEREF(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var))) \
190 {}; typedef BOOST_PP_TUPLE_ELEM(2,1,idty) \
191 BOOST_SCOPE_EXIT_AUX_WRAPPED(BOOST_PP_TUPLE_ELEM(2,0,idty), i)::type \
192 BOOST_SCOPE_EXIT_AUX_CAPTURE_T(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var);
193
194 #elif defined(BOOST_INTEL)
195
196 #define BOOST_SCOPE_EXIT_AUX_CAPTURE_DECL(r, idty, i, var) \
197 typedef BOOST_TYPEOF_KEYWORD( \
198 BOOST_SCOPE_EXIT_AUX_DEREF(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var)) \
199 BOOST_SCOPE_EXIT_AUX_CAPTURE_T(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var);
200
201 #else
202
203 #define BOOST_SCOPE_EXIT_AUX_CAPTURE_DECL(r, idty, i, var) \
204 typedef BOOST_TYPEOF(boost::scope_exit::aux::wrap( \
205 BOOST_SCOPE_EXIT_AUX_DEREF(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var))) \
206 BOOST_SCOPE_EXIT_AUX_WRAPPED(BOOST_PP_TUPLE_ELEM(2,0,idty), i); \
207 typedef BOOST_PP_TUPLE_ELEM(2,1,idty) \
208 BOOST_SCOPE_EXIT_AUX_WRAPPED(BOOST_PP_TUPLE_ELEM(2,0,idty), i)::type \
209 BOOST_SCOPE_EXIT_AUX_CAPTURE_T(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var);
210
211 #endif
212
213 #define BOOST_SCOPE_EXIT_AUX_PARAM_DECL(r, idty, i, var) \
214 typedef BOOST_SCOPE_EXIT_AUX_CAPTURE_T( \
215 BOOST_PP_TUPLE_ELEM(2,0,idty), i, var) \
216 BOOST_SCOPE_EXIT_AUX_PARAM_T(BOOST_PP_TUPLE_ELEM(2,0,idty), i, var);
217
218
219 #define BOOST_SCOPE_EXIT_AUX_IMPL(id, seq, ty) \
220 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_TAG_DECL, id, seq) \
221 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_CAPTURE_DECL, (id,ty), seq) \
222 struct BOOST_SCOPE_EXIT_AUX_PARAMS_T(id) { \
223 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_PARAM_DECL, (id,ty), seq) \
224 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_MEMBER, id, seq) \
225 BOOST_SCOPE_EXIT_AUX_PARAMS_T_CTOR(id, seq) \
226 } BOOST_SCOPE_EXIT_AUX_PARAMS(id) BOOST_SCOPE_EXIT_AUX_PARAMS_INIT(id,seq) \
227 boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< \
228 sizeof(boost_scope_exit_args)>::cmp1<0>::cmp2 > boost_scope_exit_args; \
229 boost_scope_exit_args.value = &BOOST_SCOPE_EXIT_AUX_PARAMS(id); \
230 struct BOOST_SCOPE_EXIT_AUX_GUARD_T(id) { \
231 BOOST_SCOPE_EXIT_AUX_PARAMS_T(id)* boost_se_params_; \
232 BOOST_SCOPE_EXIT_AUX_GUARD_T(id) (void* boost_se_params) \
233 : boost_se_params_( \
234 (BOOST_SCOPE_EXIT_AUX_PARAMS_T(id)*)boost_se_params) \
235 {} \
236 ~BOOST_SCOPE_EXIT_AUX_GUARD_T(id)() { boost_se_body( \
237 BOOST_PP_SEQ_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_ARG, id, seq) ); } \
238 static void boost_se_body(BOOST_PP_SEQ_FOR_EACH_I( \
239 BOOST_SCOPE_EXIT_AUX_ARG_DECL, (id,ty), seq) )
240
241 #if defined(BOOST_MSVC)
242
243 #define BOOST_SCOPE_EXIT_END } BOOST_SCOPE_EXIT_AUX_GUARD(__COUNTER__) ( \
244 boost_scope_exit_args.value);
245
246 #define BOOST_SCOPE_EXIT(seq) \
247 BOOST_SCOPE_EXIT_AUX_IMPL(__COUNTER__, seq, BOOST_PP_EMPTY())
248
249 #else
250
251 #define BOOST_SCOPE_EXIT_END } BOOST_SCOPE_EXIT_AUX_GUARD(__LINE__) ( \
252 boost_scope_exit_args.value);
253
254 #define BOOST_SCOPE_EXIT(seq) \
255 BOOST_SCOPE_EXIT_AUX_IMPL(__LINE__, seq, BOOST_PP_EMPTY())
256
257 #endif
258
259 #ifdef BOOST_SCOPE_EXIT_AUX_TPL_WORKAROUND
260 #define BOOST_SCOPE_EXIT_TPL(seq) \
261 BOOST_SCOPE_EXIT_AUX_IMPL(__LINE__, seq, typename)
262 #else
263 #define BOOST_SCOPE_EXIT_TPL(seq) BOOST_SCOPE_EXIT(seq)
264 #endif
265
266 #endif // #ifndef FILE_boost_scope_exit_hpp_INCLUDED
267
268