libmoost
/home/mhx/git/github/libmoost/include/moost/utils/scope_exit.hpp
Go to the documentation of this file.
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__