libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00039 #ifndef MOOST_UTILS_SCOPE_EXIT_HPP__ 00040 #define MOOST_UTILS_SCOPE_EXIT_HPP__ 00041 00042 #include <boost/noncopyable.hpp> 00043 #include <boost/function.hpp> 00044 #include <boost/ref.hpp> 00045 00046 namespace moost { namespace utils { 00047 00048 // These are the default policies, use on or create your own. 00049 00050 namespace scope_exit 00051 { 00052 namespace policy 00053 { 00054 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00056 template <typename scopedT> 00057 struct policy_base : private boost::noncopyable 00058 { 00059 typedef scopedT scoped_type; 00060 00061 explicit policy_base(scoped_type const & scoped) 00062 : scoped_(scoped) { } 00063 00064 protected: 00065 scoped_type scoped_; 00066 }; 00067 00068 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00070 template <typename scopedT> 00071 struct policy_base_with_get : policy_base<scopedT> 00072 { 00073 typedef scopedT scoped_type; 00074 00075 explicit policy_base_with_get(scoped_type const & scoped) 00076 : policy_base<scopedT>(scoped) { } 00077 00078 scoped_type const & get() const 00079 { 00080 return this->scoped_; 00081 } 00082 }; 00083 00084 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00086 template <typename scopedT> 00087 struct set_default_value : policy_base<boost::reference_wrapper<scopedT> > 00088 { 00089 typedef scopedT scoped_type; 00090 typedef boost::reference_wrapper<scopedT> policy_type; 00091 00092 explicit set_default_value(scoped_type & scoped) : 00093 policy_base<policy_type>(policy_type(scoped)) { } 00094 00095 void operator()() const 00096 { 00097 // Set back to default constructed value 00098 this->scoped_.get() = typename boost::remove_cv<scoped_type>::type(); 00099 } 00100 }; 00101 00102 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00104 template <typename scopedT> 00105 struct set_specific_value : policy_base<boost::reference_wrapper<scopedT> > 00106 { 00107 typedef scopedT scoped_type; 00108 typedef boost::reference_wrapper<scopedT> policy_type; 00109 00110 set_specific_value(scoped_type & scoped, scoped_type const & val) : 00111 policy_base<policy_type>(policy_type(scoped)), val_(val) { } 00112 00113 void operator()() const 00114 { 00115 // Set back to default constructed value 00116 this->scoped_.get() = val_; 00117 } 00118 00119 private: 00120 scopedT val_; 00121 }; 00122 00123 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00125 template <typename scopedT> 00126 struct restore_original_value : policy_base<boost::reference_wrapper<scopedT> > 00127 { 00128 typedef scopedT scoped_type; 00129 typedef boost::reference_wrapper<scopedT> policy_type; 00130 00131 explicit restore_original_value(scoped_type & scoped) : 00132 policy_base<policy_type>(policy_type(scoped)), orig_scoped_(scoped) 00133 { 00134 // This policy takes a copy of the original scoped type to restore later 00135 } 00136 00137 void operator()() const 00138 { 00139 // Set back to original value 00140 this->scoped_.get() = orig_scoped_; 00141 } 00142 00143 private: 00144 scoped_type const orig_scoped_; 00145 }; 00146 00147 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00150 template <typename scopedT> 00151 struct call_member_function : policy_base<boost::reference_wrapper<scopedT> > 00152 { 00153 typedef scopedT scoped_type; 00154 typedef boost::reference_wrapper<scopedT> policy_type; 00155 typedef void (scoped_type::*member_func_t)(); 00156 00157 call_member_function(scoped_type & scoped, member_func_t mf) 00158 : policy_base<policy_type>(policy_type(scoped)), mf_(mf) 00159 { 00160 } 00161 00162 explicit call_member_function(scoped_type & scoped) 00163 : policy_base<policy_type>(policy_type(scoped)), mf_(&scoped_type::operator()) 00164 { 00165 } 00166 00167 void operator()() const 00168 { 00169 if (mf_) 00170 { 00171 // call member function on scoped object 00172 (this->scoped_.get().*mf_)(); 00173 } 00174 } 00175 00176 private: 00177 member_func_t mf_; 00178 }; 00179 00180 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00182 template <typename scopedT> 00183 struct call_member_function<scopedT *> : policy_base<scopedT *> 00184 { 00185 typedef scopedT * scoped_type; 00186 typedef scoped_type policy_type; 00187 typedef void (scopedT::*member_func_t)(); 00188 00189 call_member_function(scoped_type scoped, member_func_t mf) 00190 : policy_base<policy_type>(scoped), mf_(mf) 00191 { 00192 } 00193 00194 explicit call_member_function(scoped_type scoped) 00195 : policy_base<policy_type>(scoped), mf_(&scopedT::operator()) 00196 { 00197 } 00198 00199 void operator()() const 00200 { 00201 if (mf_) 00202 { 00203 // call member function on scoped object 00204 (this->scoped_->*mf_)(); 00205 } 00206 } 00207 00208 private: 00209 member_func_t mf_; 00210 }; 00211 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00213 template <typename scopedT> 00214 struct call_free_function_with_val : policy_base_with_get<scopedT> 00215 { 00216 typedef scopedT scoped_type; 00217 typedef scopedT policy_type; 00218 typedef boost::function<void(scoped_type const &)> func_t; 00219 00220 call_free_function_with_val(scoped_type const & scoped, func_t f_) 00221 : policy_base_with_get<policy_type>(scoped), f_(f_) 00222 { 00223 } 00224 00225 void operator()() const 00226 { 00227 if (f_) 00228 { 00229 // call free function with scoped object 00230 f_(this->scoped_); 00231 } 00232 } 00233 00234 private: 00235 func_t f_; 00236 }; 00237 00238 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00240 template <typename scopedT> 00241 struct call_free_function_with_ref : policy_base_with_get<boost::reference_wrapper<scopedT> > 00242 { 00243 typedef scopedT scoped_type; 00244 typedef boost::reference_wrapper<scopedT> policy_type; 00245 typedef boost::function<void(scoped_type &)> func_t; 00246 00247 call_free_function_with_ref(scoped_type & scoped, func_t f_) 00248 : policy_base_with_get<policy_type>(policy_type(scoped)), f_(f_) 00249 { 00250 } 00251 00252 void operator()() const 00253 { 00254 if (f_) 00255 { 00256 // call free function with scoped object 00257 f_(this->scoped_.get()); 00258 } 00259 } 00260 00261 private: 00262 func_t f_; 00263 }; 00264 00265 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00267 template <typename scopedT> 00268 struct free_malloc : call_free_function_with_val<scopedT *> 00269 { 00270 typedef scopedT * scoped_type; 00271 typedef scoped_type policy_type; 00272 typedef call_free_function_with_val<scopedT *> base_policy; 00273 00274 explicit free_malloc(scoped_type const & scoped) 00275 : call_free_function_with_val<scoped_type>(scoped, ::free) 00276 { 00277 // [6/4/2011 ricky] Yes, I'm afraid you *will* have to cast the direct output from malloc 00278 // to that of the scoped type. This is C++ not C so get over it. Besides, 00279 // what are you playing at using malloc anyway in C++ You'd better have a 00280 // darn good reason or the code police will be on your case. Hope you know 00281 // exactly what you're getting yourself into here - good luck :) 00282 // 00283 // PS. I did consider adding a void * constructor but that would have 00284 // lead to a situation where you could declare a scoped pointer to 00285 // one type and then initialise things with a pointer to another. 00286 // This would have been a recipe for disaster do I didn't =/ 00287 } 00288 }; 00289 00290 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00292 struct call_functor : policy_base<boost::function0<void> > 00293 { 00294 typedef boost::function0<void> scoped_type; 00295 typedef scoped_type policy_type; 00296 00297 explicit call_functor(scoped_type const & scoped) 00298 : policy_base<policy_type>(policy_type(scoped)) 00299 { 00300 } 00301 00302 void operator()() const 00303 { 00304 if (this->scoped_) 00305 { 00306 this->scoped_(); 00307 } 00308 } 00309 }; 00310 00311 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00312 // *** OR CREATE YOUR OWN POLICY AS REQUIRED 00313 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 00314 } 00315 00317 00318 template < 00319 typename policyT 00320 > 00321 struct basic_scope_exit 00322 { 00323 typedef policyT policy_t; 00324 typedef typename policy_t::policy_type policy_type; 00325 typedef typename policy_t::scoped_type scoped_type; 00326 00327 template<typename scoped_typeT> 00328 explicit basic_scope_exit(scoped_typeT & scoped) : 00329 exit_policy_(scoped), cancel_(false) 00330 { 00331 } 00332 00333 template<typename scoped_typeT> 00334 explicit basic_scope_exit(scoped_typeT const & scoped) : 00335 exit_policy_(scoped), cancel_(false) 00336 { 00337 } 00338 00339 template<typename scoped_typeT, typename policy_dataT> 00340 basic_scope_exit(scoped_typeT & scoped, policy_dataT & policy_data) : 00341 exit_policy_(scoped, policy_data), cancel_(false) 00342 { 00343 } 00344 00345 template<typename scoped_typeT, typename policy_dataT> 00346 basic_scope_exit(scoped_typeT const & scoped, policy_dataT & policy_data) : 00347 exit_policy_(scoped, policy_data), cancel_(false) 00348 { 00349 } 00350 00351 template<typename scoped_typeT, typename policy_dataT> 00352 basic_scope_exit(scoped_typeT & scoped, policy_dataT const & policy_data) : 00353 exit_policy_(scoped, policy_data), cancel_(false) 00354 { 00355 } 00356 00357 template<typename scoped_typeT, typename policy_dataT> 00358 basic_scope_exit(scoped_typeT const & scoped, policy_dataT const & policy_data) : 00359 exit_policy_(scoped, policy_data), cancel_(false) 00360 { 00361 } 00362 00363 basic_scope_exit & operator = (policy_t const & exit_policy) 00364 { 00365 exit_policy_ = exit_policy; 00366 } 00367 00368 void cancel(bool cancel = true) 00369 { 00370 cancel_ = cancel; 00371 } 00372 00373 bool is_cancelled() const 00374 { 00375 return cancel_; 00376 } 00377 00378 policy_t & operator *() 00379 { 00380 return exit_policy_; 00381 } 00382 00383 policy_t const & operator *() const 00384 { 00385 return exit_policy_; 00386 } 00387 00388 policy_t * operator ->() 00389 { 00390 return &exit_policy_; 00391 } 00392 00393 policy_t const * operator ->() const 00394 { 00395 return &exit_policy_; 00396 } 00397 00398 ~basic_scope_exit() 00399 { 00400 try 00401 { 00402 if(!cancel_) exit_policy_(); 00403 } 00404 catch(...) {} 00405 } 00406 00407 private: 00408 policy_t exit_policy_; 00409 bool cancel_; 00410 }; 00411 00412 00414 typedef basic_scope_exit<policy::call_functor> call_functor; 00415 00417 template <typename scopedT> 00418 struct type 00419 { 00421 typedef basic_scope_exit<policy::set_default_value<scopedT> > set_default_value; 00422 00424 typedef basic_scope_exit<policy::set_specific_value<scopedT> > set_specific_value; 00425 00427 typedef basic_scope_exit<policy::restore_original_value<scopedT> > restore_original_value; 00428 00430 typedef basic_scope_exit<policy::call_member_function<scopedT> > call_member_function; 00431 00433 typedef basic_scope_exit<policy::call_free_function_with_val<scopedT> > call_free_function_with_val; 00434 00436 typedef basic_scope_exit<policy::call_free_function_with_ref<scopedT> > call_free_function_with_ref; 00437 00439 typedef basic_scope_exit<policy::free_malloc<scopedT> > free_malloc; 00440 00441 private: type(); 00442 }; 00443 } 00444 }} 00445 00446 #endif // MOOST_UTILS_SCOPE_EXIT_HPP__