unwind-prot.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2009-2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #if !defined (octave_unwind_prot_h)
00025 #define octave_unwind_prot_h 1
00026 
00027 #include <cstddef>
00028 
00029 #include <string>
00030 #include <memory>
00031 
00032 // This class allows registering cleanup actions.
00033 class
00034 OCTINTERP_API
00035 unwind_protect
00036 {
00037 public:
00038 
00039   // A generic unwind_protect element. Knows how to run itself and discard itself.
00040   // Also, contains a pointer to the next element.
00041   class elem
00042   {
00043     elem *next;
00044 
00045   public:
00046     elem (void) : next (0) { }
00047 
00048     virtual void run (void) { }
00049 
00050     virtual ~elem (void) { }
00051 
00052     friend class unwind_protect;
00053 
00054   private:
00055 
00056     // No copying!
00057 
00058     elem (const elem&);
00059 
00060     elem& operator = (const elem&);
00061   };
00062 
00063   // An element that merely runs a void (*)(void) function.
00064 
00065   class fcn_elem : public elem
00066   {
00067   public:
00068     fcn_elem (void (*fptr) (void))
00069       : e_fptr (fptr) { }
00070 
00071     void run (void) { e_fptr (); }
00072 
00073   private:
00074     void (*e_fptr) (void);
00075   };
00076 
00077   // An element that stores a variable of type T along with a void (*) (T)
00078   // function pointer, and calls the function with the parameter.
00079 
00080   template <class T>
00081   class fcn_arg_elem : public elem
00082   {
00083   public:
00084     fcn_arg_elem (void (*fcn) (T), T arg)
00085       : e_fcn (fcn), e_arg (arg) { }
00086 
00087     void run (void) { e_fcn (e_arg); }
00088 
00089   private:
00090 
00091     // No copying!
00092 
00093     fcn_arg_elem (const fcn_arg_elem&);
00094 
00095     fcn_arg_elem& operator = (const fcn_arg_elem&);
00096 
00097     void (*e_fcn) (T);
00098     T e_arg;
00099   };
00100 
00101   // An element that stores a variable of type T along with a void (*) (const T&)
00102   // function pointer, and calls the function with the parameter.
00103 
00104   template <class T>
00105   class fcn_crefarg_elem : public elem
00106   {
00107   public:
00108     fcn_crefarg_elem (void (*fcn) (const T&), T arg)
00109       : e_fcn (fcn), e_arg (arg) { }
00110 
00111     void run (void) { e_fcn (e_arg); }
00112 
00113   private:
00114     void (*e_fcn) (const T&);
00115     T e_arg;
00116   };
00117 
00118   // An element for calling a member function.
00119 
00120   template <class T>
00121   class method_elem : public elem
00122   {
00123   public:
00124     method_elem (T *obj, void (T::*method) (void))
00125       : e_obj (obj), e_method (method) { }
00126 
00127     void run (void) { (e_obj->*e_method) (); }
00128 
00129   private:
00130 
00131     T *e_obj;
00132     void (T::*e_method) (void);
00133 
00134     // No copying!
00135 
00136     method_elem (const method_elem&);
00137 
00138     method_elem operator = (const method_elem&);
00139   };
00140 
00141   // An element that stores arbitrary variable, and restores it.
00142 
00143   template <class T>
00144   class restore_var_elem : public elem
00145   {
00146   public:
00147     restore_var_elem (T& ref, const T& val)
00148       : e_ptr (&ref), e_val (val) { }
00149 
00150     void run (void) { *e_ptr = e_val; }
00151 
00152   private:
00153 
00154     // No copying!
00155 
00156     restore_var_elem (const restore_var_elem&);
00157 
00158     restore_var_elem& operator = (const restore_var_elem&);
00159 
00160     T *e_ptr, e_val;
00161   };
00162 
00163   // Deletes a class allocated using new.
00164 
00165   template <class T>
00166   class delete_ptr_elem : public elem
00167   {
00168   public:
00169     delete_ptr_elem (T *ptr)
00170       : e_ptr (ptr) { }
00171 
00172     void run (void) { delete e_ptr; }
00173 
00174   private:
00175 
00176     T *e_ptr;
00177 
00178     // No copying!
00179 
00180     delete_ptr_elem (const delete_ptr_elem&);
00181 
00182     delete_ptr_elem operator = (const delete_ptr_elem&);
00183   };
00184 
00185   unwind_protect (void) : head () { }
00186 
00187   void add (elem *new_elem)
00188     {
00189       new_elem->next = head;
00190       head = new_elem;
00191     }
00192 
00193   // For backward compatibility.
00194   void add (void (*fcn) (void *), void *ptr = 0)
00195     {
00196       add (new fcn_arg_elem<void *> (fcn, ptr));
00197     }
00198 
00199   // Call to void func (void).
00200   void add_fcn (void (*fcn) (void))
00201     {
00202       add (new fcn_elem (fcn));
00203     }
00204 
00205   // Call to void func (T).
00206   template <class T>
00207   void add_fcn (void (*action) (T), T val)
00208     {
00209       add (new fcn_arg_elem<T> (action, val));
00210     }
00211 
00212   // Call to void func (const T&).
00213   template <class T>
00214   void add_fcn (void (*action) (const T&), T val)
00215     {
00216       add (new fcn_crefarg_elem<T> (action, val));
00217     }
00218 
00219   // Call to T::method (void).
00220   template <class T>
00221   void add_method (T *obj, void (T::*method) (void))
00222     {
00223       add (new method_elem<T> (obj, method));
00224     }
00225 
00226   // Call to delete (T*).
00227 
00228   template <class T>
00229   void add_delete (T *obj)
00230     {
00231       add (new delete_ptr_elem<T> (obj));
00232     }
00233 
00234   // Protect any variable.
00235   template <class T>
00236   void protect_var (T& var)
00237     {
00238       add (new restore_var_elem<T> (var, var));
00239     }
00240 
00241   // Protect any variable, value given.
00242   template <class T>
00243   void protect_var (T& var, const T& val)
00244     {
00245       add (new restore_var_elem<T> (var, val));
00246     }
00247 
00248   operator bool (void) const
00249     {
00250       return head != 0;
00251     }
00252 
00253   void run_top (void)
00254     {
00255       if (head)
00256         {
00257           // No leak on exception!
00258           std::auto_ptr<elem> ptr (head);
00259           head = ptr->next;
00260           ptr->run ();
00261         }
00262     }
00263 
00264   void run_top (int num)
00265     {
00266       while (num-- > 0)
00267         run_top ();
00268     }
00269 
00270   void discard_top (void)
00271     {
00272       if (head)
00273         {
00274           elem *ptr = head;
00275           head = ptr->next;
00276           delete ptr;
00277         }
00278     }
00279 
00280   void discard_top (int num)
00281     {
00282       while (num-- > 0)
00283         discard_top ();
00284     }
00285 
00286   void run (void)
00287     {
00288       while (head)
00289         run_top ();
00290     }
00291 
00292   void discard (void)
00293     {
00294       while (head)
00295         discard_top ();
00296     }
00297 
00298   // Destructor should not raise an exception, so all actions registered should
00299   // be exception-safe (but setting error_state is allowed). If you're not sure,
00300   // see unwind_protect_safe.
00301   ~unwind_protect (void)
00302     {
00303       run ();
00304     }
00305 
00306 private:
00307 
00308   elem *head;
00309 
00310   // No copying!
00311 
00312   unwind_protect (const unwind_protect&);
00313 
00314   unwind_protect& operator = (const unwind_protect&);
00315 };
00316 
00317 // Like unwind_protect, but this one will guard against the possibility of seeing
00318 // an exception (or interrupt) in the cleanup actions. Not that we can do much about
00319 // it, but at least we won't crash.
00320 
00321 class
00322 OCTINTERP_API
00323 unwind_protect_safe : public unwind_protect
00324 {
00325   static void gripe_exception (void);
00326 
00327 public:
00328   ~unwind_protect_safe (void)
00329     {
00330       while (*this)
00331         {
00332           try
00333             {
00334               run_top ();
00335             }
00336           catch (...) // Yes, the black hole. Remember we're in a dtor.
00337             {
00338               gripe_exception ();
00339             }
00340         }
00341     }
00342 };
00343 
00344 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines