OLD | NEW |
| (Empty) |
1 // | |
2 // Author: Andrei Alexandrescu - andrei@metalanguage.com | |
3 // | |
4 // The code below is based on the following article published in | |
5 // C/C++ Users Journal by Andrei Alexandrescu: | |
6 // | |
7 // http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm | |
8 // | |
9 // ScopeGuard is useful when you need to perform automatic cleanup of resources. | |
10 // This idiom is important when you want to assemble an operation out of several | |
11 // atomic operations, each of which could fail. | |
12 // | |
13 // Usage | |
14 // ------ | |
15 // Scope guard for objects: | |
16 // void f(T& t) { | |
17 // std::vector<T> v; | |
18 // v.push_back(t); | |
19 // ScopeGuard guard = MakeObjGuard(v, &std::vector<T>v::pop_back); | |
20 // if (!Commit()) { | |
21 // return; | |
22 // } | |
23 // guard.Dismiss(); // removes the t from the vector in the case Commit fa
ils | |
24 // } | |
25 // | |
26 // Scope guard for functions: | |
27 // void open(); | |
28 // void close(int i); | |
29 // void g(int i) { | |
30 // open(); | |
31 // ScopeGuard guard = MakeGuard(close, 0); | |
32 // if (!read()) { | |
33 // return; | |
34 // } | |
35 // if (!write()) { | |
36 // return; | |
37 // } | |
38 // } | |
39 // | |
40 // Using the macros: | |
41 // void g(int i) { | |
42 // open(); | |
43 // ON_SCOPE_EXIT(close, 0); | |
44 // if (!read()) { | |
45 // return; | |
46 // } | |
47 // if (!write()) { | |
48 // return; | |
49 // } | |
50 // } | |
51 | |
52 // TODO(omaha): provide support to run with or without exceptions enabled. | |
53 // For now it assumes that the code is not throwing exceptions. | |
54 #ifndef SCOPEGUARD_H_ | |
55 #define SCOPEGUARD_H_ | |
56 | |
57 namespace omaha { | |
58 | |
59 template <class T> | |
60 class RefHolder | |
61 { | |
62 T& ref_; | |
63 public: | |
64 RefHolder(T& ref) : ref_(ref) {} | |
65 operator T& () const | |
66 { | |
67 return ref_; | |
68 } | |
69 private: | |
70 // Disable assignment - not implemented | |
71 RefHolder& operator=(const RefHolder&); | |
72 }; | |
73 | |
74 template <class T> | |
75 inline RefHolder<T> ByRef(T& t) | |
76 { | |
77 return RefHolder<T>(t); | |
78 } | |
79 | |
80 class ScopeGuardImplBase | |
81 { | |
82 ScopeGuardImplBase& operator =(const ScopeGuardImplBase&); | |
83 protected: | |
84 ~ScopeGuardImplBase() | |
85 { | |
86 } | |
87 ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() | |
88 : dismissed_(other.dismissed_) | |
89 { | |
90 other.Dismiss(); | |
91 } | |
92 template <typename J> | |
93 static void SafeExecute(J& j) throw() | |
94 { | |
95 if (!j.dismissed_) | |
96 { | |
97 // TODO(omaha): assume this does not throw | |
98 j.Execute(); | |
99 } | |
100 } | |
101 | |
102 mutable bool dismissed_; | |
103 public: | |
104 ScopeGuardImplBase() throw() : dismissed_(false) | |
105 { | |
106 } | |
107 void Dismiss() const throw() | |
108 { | |
109 dismissed_ = true; | |
110 } | |
111 }; | |
112 | |
113 typedef const ScopeGuardImplBase& ScopeGuard; | |
114 | |
115 template <typename F> | |
116 class ScopeGuardImpl0 : public ScopeGuardImplBase | |
117 { | |
118 public: | |
119 static ScopeGuardImpl0<F> MakeGuard(F fun) | |
120 { | |
121 return ScopeGuardImpl0<F>(fun); | |
122 } | |
123 ~ScopeGuardImpl0() throw() | |
124 { | |
125 SafeExecute(*this); | |
126 } | |
127 void Execute() | |
128 { | |
129 fun_(); | |
130 } | |
131 protected: | |
132 ScopeGuardImpl0(F fun) : fun_(fun) | |
133 { | |
134 } | |
135 F fun_; | |
136 }; | |
137 | |
138 template <typename F> | |
139 inline ScopeGuardImpl0<F> MakeGuard(F fun) | |
140 { | |
141 return ScopeGuardImpl0<F>::MakeGuard(fun); | |
142 } | |
143 | |
144 template <typename F, typename P1> | |
145 class ScopeGuardImpl1 : public ScopeGuardImplBase | |
146 { | |
147 public: | |
148 static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) | |
149 { | |
150 return ScopeGuardImpl1<F, P1>(fun, p1); | |
151 } | |
152 ~ScopeGuardImpl1() throw() | |
153 { | |
154 SafeExecute(*this); | |
155 } | |
156 void Execute() | |
157 { | |
158 fun_(p1_); | |
159 } | |
160 protected: | |
161 ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) | |
162 { | |
163 } | |
164 F fun_; | |
165 const P1 p1_; | |
166 }; | |
167 | |
168 template <typename F, typename P1> | |
169 inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) | |
170 { | |
171 return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1); | |
172 } | |
173 | |
174 template <typename F, typename P1, typename P2> | |
175 class ScopeGuardImpl2: public ScopeGuardImplBase | |
176 { | |
177 public: | |
178 static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) | |
179 { | |
180 return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2); | |
181 } | |
182 ~ScopeGuardImpl2() throw() | |
183 { | |
184 SafeExecute(*this); | |
185 } | |
186 void Execute() | |
187 { | |
188 fun_(p1_, p2_); | |
189 } | |
190 protected: | |
191 ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) | |
192 { | |
193 } | |
194 F fun_; | |
195 const P1 p1_; | |
196 const P2 p2_; | |
197 }; | |
198 | |
199 template <typename F, typename P1, typename P2> | |
200 inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) | |
201 { | |
202 return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2); | |
203 } | |
204 | |
205 template <typename F, typename P1, typename P2, typename P3> | |
206 class ScopeGuardImpl3 : public ScopeGuardImplBase | |
207 { | |
208 public: | |
209 static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) | |
210 { | |
211 return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3); | |
212 } | |
213 ~ScopeGuardImpl3() throw() | |
214 { | |
215 SafeExecute(*this); | |
216 } | |
217 void Execute() | |
218 { | |
219 fun_(p1_, p2_, p3_); | |
220 } | |
221 protected: | |
222 ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_
(p3) | |
223 { | |
224 } | |
225 F fun_; | |
226 const P1 p1_; | |
227 const P2 p2_; | |
228 const P3 p3_; | |
229 }; | |
230 | |
231 template <typename F, typename P1, typename P2, typename P3> | |
232 inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) | |
233 { | |
234 return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3); | |
235 } | |
236 | |
237 | |
238 template <class Obj, typename MemFun> | |
239 class ObjScopeGuardImpl0 : public ScopeGuardImplBase | |
240 { | |
241 public: | |
242 static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) | |
243 { | |
244 return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun); | |
245 } | |
246 ~ObjScopeGuardImpl0() throw() | |
247 { | |
248 SafeExecute(*this); | |
249 } | |
250 void Execute() | |
251 { | |
252 (obj_.*memFun_)(); | |
253 } | |
254 protected: | |
255 ObjScopeGuardImpl0(Obj& obj, MemFun memFun) | |
256 : obj_(obj), memFun_(memFun) {} | |
257 Obj& obj_; | |
258 MemFun memFun_; | |
259 }; | |
260 | |
261 template <class Obj, typename MemFun> | |
262 inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) | |
263 { | |
264 return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun); | |
265 } | |
266 | |
267 template <class Obj, typename MemFun, typename P1> | |
268 class ObjScopeGuardImpl1 : public ScopeGuardImplBase | |
269 { | |
270 public: | |
271 static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFu
n, P1 p1) | |
272 { | |
273 return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1); | |
274 } | |
275 ~ObjScopeGuardImpl1() throw() | |
276 { | |
277 SafeExecute(*this); | |
278 } | |
279 void Execute() | |
280 { | |
281 (obj_.*memFun_)(p1_); | |
282 } | |
283 protected: | |
284 ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) | |
285 : obj_(obj), memFun_(memFun), p1_(p1) {} | |
286 Obj& obj_; | |
287 MemFun memFun_; | |
288 const P1 p1_; | |
289 }; | |
290 | |
291 template <class Obj, typename MemFun, typename P1> | |
292 inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun,
P1 p1) | |
293 { | |
294 return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1); | |
295 } | |
296 | |
297 template <class Obj, typename MemFun, typename P1, typename P2> | |
298 class ObjScopeGuardImpl2 : public ScopeGuardImplBase | |
299 { | |
300 public: | |
301 static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun m
emFun, P1 p1, P2 p2) | |
302 { | |
303 return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2); | |
304 } | |
305 ~ObjScopeGuardImpl2() throw() | |
306 { | |
307 SafeExecute(*this); | |
308 } | |
309 void Execute() | |
310 { | |
311 (obj_.*memFun_)(p1_, p2_); | |
312 } | |
313 protected: | |
314 ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) | |
315 : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {} | |
316 Obj& obj_; | |
317 MemFun memFun_; | |
318 const P1 p1_; | |
319 const P2 p2_; | |
320 }; | |
321 | |
322 template <class Obj, typename MemFun, typename P1, typename P2> | |
323 inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun mem
Fun, P1 p1, P2 p2) | |
324 { | |
325 return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1,
p2); | |
326 } | |
327 | |
328 template <class Obj, typename MemFun, typename P1, typename P2, typename P3> | |
329 class ObjScopeGuardImpl3 : public ScopeGuardImplBase | |
330 { | |
331 public: | |
332 static ObjScopeGuardImpl3<Obj, MemFun, P1, P2, P3> MakeObjGuard(Obj& obj, MemF
un memFun, P1 p1, P2 p2, P3 p3) | |
333 { | |
334 return ObjScopeGuardImpl3<Obj, MemFun, P1, P2, P3>(obj, memFun, p1, p2, p3); | |
335 } | |
336 ~ObjScopeGuardImpl3() throw() | |
337 { | |
338 SafeExecute(*this); | |
339 } | |
340 void Execute() | |
341 { | |
342 (obj_.*memFun_)(p1_, p2_, p3_); | |
343 } | |
344 protected: | |
345 ObjScopeGuardImpl3(Obj& obj, MemFun memFun, P1 p1, P2 p2, P3 p3) | |
346 : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2), p3_(p3) {} | |
347 Obj& obj_; | |
348 MemFun memFun_; | |
349 const P1 p1_; | |
350 const P2 p2_; | |
351 const P3 p3_; | |
352 }; | |
353 | |
354 template <class Obj, typename MemFun, typename P1, typename P2, typename P3> | |
355 inline ObjScopeGuardImpl3<Obj, MemFun, P1, P2, P3> MakeObjGuard(Obj& obj, MemFun
memFun, P1 p1, P2 p2, P3 p3) | |
356 { | |
357 return ObjScopeGuardImpl3<Obj, MemFun, P1, P2, P3>::MakeObjGuard(obj, memFun,
p1, p2, p3); | |
358 } | |
359 | |
360 #define CONCATENATE_DIRECT(s1, s2) s1##s2 | |
361 #define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2) | |
362 #define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__) | |
363 | |
364 #define ON_SCOPE_EXIT ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard | |
365 #define ON_SCOPE_EXIT_OBJ ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGua
rd | |
366 | |
367 } // namespace omaha | |
368 | |
369 #endif //SCOPEGUARD_H_ | |
OLD | NEW |