changeset 9394:b3ab22ee8544

further improve unwind_protect
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 25 Jun 2009 08:47:24 +0200
parents d6c99b2ee941
children 1de00ca9c9f2
files src/ChangeLog src/unwind-prot.cc src/unwind-prot.h
diffstat 3 files changed, 81 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,18 @@
+2009-06-25  Jaroslav Hajek  <highegg@gmail.com>
+
+	* unwind-prot.h (unwind_protect::elem): New polymorphic class.
+	(unwind_protect::restore_var): Remove.
+	(unwind_protect::restore_mem): Remove.
+	(unwind_protect::elt_list): Update.
+	(unwind_protect::add (elem *)): New method.
+	(unwind_protect::add (void (*)(void *), void *)): Reimplement.
+	(unwind_protect::run (void)): Rewrite.
+	(unwind_protect::discard (void)): Rewrite.
+	(unwind_protect::protect_var): Rewrite.
+	(unwind_protect::protect_mem): Rewrite.
+	(unwind_protect::add_action_var): New method.
+	* unwind-prot.cc (unwind_protect::restore_mem): Remove.
+
 2009-06-24  Thorsten Meyer  <thorsten.meyier@gmx.de>
 
 	* oct-map.cc (Octave_map::squeeze, Octave_map::permute,
--- a/src/unwind-prot.cc
+++ b/src/unwind-prot.cc
@@ -33,22 +33,10 @@
 #include "unwind-prot.h"
 #include "utils.h"
 
-std::stack<unwind_protect::elem> unwind_protect::elt_list;
+std::stack<unwind_protect::elem *> unwind_protect::elt_list;
 
 std::stack<std::pair <std::string, unwind_protect::frame_id_t> > unwind_protect::tag_list;
 
-unwind_protect::restore_mem::restore_mem (void *ptr, size_t size)
-  : rptr (ptr), sptr (reinterpret_cast<void *> (new char[size])), rsize (size)
-{
-  std::memcpy (sptr, rptr, size);
-}
-
-unwind_protect::restore_mem::~restore_mem (void)
-{
-  std::memcpy (rptr, sptr, rsize);
-  delete [] reinterpret_cast<char *> (sptr);
-}
-
 void
 unwind_protect::begin_frame (const std::string& tag)
 {
--- a/src/unwind-prot.h
+++ b/src/unwind-prot.h
@@ -29,7 +29,7 @@
 
 #include <string>
 #include <stack>
-#include <utility>
+#include <memory>
 
 class
 OCTINTERP_API
@@ -37,86 +37,89 @@
 {
 public:
 
-  // This template class can be used to restore value of a variable of any
-  // class posessing a copy constructor and assignment operator.
-
-  template <class T>
-  class
-  restore_var
+  // A generic unwind_protect element. Knows how to run itself and discard itself.
+  class elem
   {
   public:
-    restore_var (T *ptr, const T& val) 
-      : rptr (ptr), rval(val) { }
-    restore_var (T *ptr) 
-      : rptr (ptr), rval(*ptr) { }
-    ~restore_var (void)
-      { *rptr = rval; }
+    virtual void run (void) { }
+    virtual ~elem (void) { }
+  };
 
-    // For unwind_protect.
-    static void cleanup (void *ptr)
-      {
-        delete reinterpret_cast<restore_var *> (ptr);
-      }
+  // An element that merely runs a void (*)(void *) function.
+  
+  class fcn_elem : public elem
+  {
+  public:
+    fcn_elem (void (*fptr) (void *), void *ptr)
+      : e_fptr (fptr), e_ptr (ptr) { }
+
+    void run (void) { e_fptr (e_ptr); }
 
   private:
-
-    // No copying!
-    restore_var (const restore_var&);
-    void operator = (const restore_var&); 
-
-    T *rptr, rval;
+    void (*e_fptr) (void *);
+    void *e_ptr;
   };
 
-  // This class is used to restore arbitrary memory area using std::memcpy.
+  // An element that stores arbitrary variable, and restores it.
 
-  class
-  restore_mem
+  template <class T>
+  class restore_var_elem : public elem
   {
   public:
-    restore_mem (void *ptr, size_t size);
-    ~restore_mem (void);
+    restore_var_elem (T& ref, const T& val)
+      : e_ptr (&ref), e_val (val) { }
 
-    // For unwind_protect.
-    static void cleanup (void *ptr)
-      {
-        delete reinterpret_cast<restore_mem *> (ptr);
-      }
+    void run (void) { *e_ptr = e_val; }
 
   private:
-
-    // No copying!
-    restore_mem (const restore_mem&);
-    void operator = (const restore_mem&); 
-
-    void *rptr, *sptr;
-    size_t rsize;
+    T *e_ptr, e_val;
   };
 
-  typedef void (*cleanup_func) (void *ptr);
+  // An element that stores a variable of type T along with a void (*) (T)
+  // function pointer, and calls the function with the parameter.
+
+  template <class T>
+  class action_var_elem : public elem
+  {
+  public:
+    action_var_elem (void (*fcn) (T), T val)
+      : e_fcn (fcn), e_val (val) { }
+
+    void run (void) { e_fcn (e_val); }
+
+  private:
+    void (*e_fcn) (T);
+    T e_val;
+  };
 
   typedef size_t frame_id_t;
 
-  typedef std::pair<cleanup_func, void *> elem;
+  // Generic. Users may subclass elem to provide their own cleanup.
+  static void add (elem *el)
+    {
+      elt_list.push (el);
+    }
 
   static bool empty (void)
     { return elt_list.empty (); }
 
-  static void add (cleanup_func fptr, void *ptr = 0)
-    {
-      elt_list.push (elem (fptr, ptr));
-    }
-
   static void run (void)
     {
-      elem elt = elt_list.top ();
+      // Use auto_ptr, so that even if the following run () call throws an
+      // exception, we still clean up the element.
+      std::auto_ptr<elem> elt (elt_list.top ());
       elt_list.pop ();
 
-      elt.first (elt.second);
+      elt->run ();
     }
 
   static void discard (void)
     {
+      // No need to use ato_ptr here.
+      elem *elt = elt_list.top ();
       elt_list.pop ();
+
+      delete elt;
     }
 
   static frame_id_t begin_frame ()
@@ -158,29 +161,35 @@
         tag_list.pop ();
     }
 
+  static void add (void (*fcn) (void *), void *ptr = 0)
+    {
+      elt_list.push (new fcn_elem (fcn, ptr));
+    }
+
   // Protect any variable.
   template <class T>
   static void protect_var (T& var)
     {
-      add (restore_var<T>::cleanup, new restore_var<T> (&var));
+      elt_list.push (new restore_var_elem<T> (var, var));
     }
 
   // Protect any variable, value given.
   template <class T>
   static void protect_var (T& var, const T& val)
     {
-      add (restore_var<T>::cleanup, new restore_var<T> (&var, val));
+      elt_list.push (new restore_var_elem<T> (var, val));
     }
 
-  // Protect an area of memory.
-  static void protect_mem (void *ptr, size_t size)
+  // Store a function pointer together with a single argument (passed by value).
+  template <class T>
+  static void add_action_var (void (*action) (T), T val)
     {
-      add (restore_mem::cleanup, new restore_mem (ptr, size));
+      elt_list.push (new action_var_elem<T> (action, val));
     }
 
 private:
 
-  static std::stack<elem> elt_list;
+  static std::stack<elem *> elt_list;
 
   static std::stack<std::pair <std::string, frame_id_t> > tag_list;
 };