diff src/unwind-prot.h @ 9376:d58086453171

refactor unwind_protect
author Jaroslav Hajek <highegg@gmail.com>
date Tue, 23 Jun 2009 07:55:44 +0200
parents eb63fbe60fab
children 8bec23396924
line wrap: on
line diff
--- a/src/unwind-prot.h	Mon Jun 22 21:00:18 2009 -0400
+++ b/src/unwind-prot.h	Tue Jun 23 07:55:44 2009 +0200
@@ -2,6 +2,7 @@
 
 Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2004,
               2005, 2006, 2007, 2008 John W. Eaton
+Copyright (C) 2009 VZLU Prague
 
 This file is part of Octave.
 
@@ -28,52 +29,7 @@
 
 #include <string>
 #include <stack>
-
-class
-OCTINTERP_API
-unwind_elem
-{
-public:
-
-  typedef void (*cleanup_func) (void *ptr);
-
-  unwind_elem (void)
-    : ue_tag (), ue_fptr (0), ue_ptr (0) { }
-
-  unwind_elem (const std::string &t)
-    : ue_tag (t), ue_fptr (0), ue_ptr (0) { }
-
-  unwind_elem (cleanup_func f, void *p)
-    : ue_tag (), ue_fptr (f), ue_ptr (p) { }
-
-  unwind_elem (const unwind_elem& el)
-    : ue_tag (el.ue_tag), ue_fptr (el.ue_fptr), ue_ptr (el.ue_ptr) { }
-
-  ~unwind_elem (void) { }
-
-  unwind_elem& operator = (const unwind_elem& el)
-    {
-      ue_tag = el.ue_tag;
-      ue_fptr = el.ue_fptr;
-      ue_ptr = el.ue_ptr;
-
-      return *this;
-    }
-
-  std::string tag (void) { return ue_tag; }
-
-  cleanup_func fptr (void) { return ue_fptr; }
-
-  void *ptr (void) { return ue_ptr; }
-
-private:
-
-  std::string ue_tag;
-
-  cleanup_func ue_fptr;
-
-  void *ue_ptr;
-};
+#include <utility>
 
 class
 OCTINTERP_API
@@ -81,64 +37,174 @@
 {
 public:
 
-  static void add (unwind_elem::cleanup_func fptr, void *ptr = 0);
+  // This template class can be used to restore value of a variable of any
+  // class posessing a copy constructor and assignment operator.
 
-  static void run (void);
+  template <class T>
+  class
+  restore_var
+  {
+  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; }
 
-  static void discard (void);
+    // For unwind_protect.
+    static void cleanup (void *ptr)
+      {
+        delete reinterpret_cast<restore_var *> (ptr);
+      }
+
+  private:
 
-  static void begin_frame (const std::string& tag);
+    // No copying!
+    void operator = (const restore_var&); 
+
+    T *rptr, rval;
+  };
+
+  // This class is used to restore arbitrary memory area using std::memcpy.
 
-  static void run_frame (const std::string& tag);
+  class
+  restore_mem
+  {
+  public:
+    restore_mem (void *ptr, size_t size);
+    ~restore_mem (void);
 
-  static void discard_frame (const std::string& tag);
+    // For unwind_protect.
+    static void cleanup (void *ptr)
+      {
+        delete reinterpret_cast<restore_mem *> (ptr);
+      }
+
+  private:
+
+    // No copying!
+    void operator = (const restore_mem&); 
 
-  static void run_all (void);
+    void *rptr, *sptr;
+    size_t rsize;
+  };
+
+  typedef void (*cleanup_func) (void *ptr);
+
+  typedef size_t frame_id_t;
+
+  typedef std::pair<cleanup_func, void *> elem;
 
-  static void discard_all (void);
+  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 ();
+      elt_list.pop ();
 
-  // Ways to save variables.
+      elt.first (elt.second);
+    }
 
-  static void save_bool (bool *ptr, bool value);
+  static void discard (void)
+    {
+      elt_list.pop ();
+    }
+
+  static frame_id_t begin_frame ()
+    {
+      return elt_list.size ();
+    }
 
-  static void save_int (int *ptr, int value);
+  static void run_frame (frame_id_t frame_id)
+    {
+      while (elt_list.size () > frame_id)
+        run ();
+    }
 
-  static void save_size_t (size_t *ptr, size_t value);
+  static void discard_frame (frame_id_t frame_id)
+    {
+      while (elt_list.size () > frame_id)
+        discard ();
+    }
+
+  // String tags are deprecated. Use the above trio.
+
+  static void begin_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
+
+  static void run_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
+
+  static void discard_frame (const std::string& tag) GCC_ATTR_DEPRECATED;
 
-  static void save_str (std::string *ptr, const std::string& value);
+  static void run_all (void)
+    { 
+      run_frame (0);
+      while (! tag_list.empty ())
+        tag_list.pop ();
+    }
 
-  static void save_ptr (void **ptr, void *value);
+  static void discard_all (void)
+    { 
+      discard_frame (0);
+      while (! tag_list.empty ())
+        tag_list.pop ();
+    }
 
-  static void save_var (void *ptr, void *value, size_t size);
+  // Protect any variable.
+  template <class T>
+  static void protect_var (T& var)
+    {
+      add (restore_var<T>::cleanup, new restore_var<T> (&var));
+    }
 
-  static std::stack<unwind_elem> elt_list;
+  // 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));
+    }
+
+  // Protect an area of memory.
+  static void protect_mem (void *ptr, size_t size)
+    {
+      add (restore_mem::cleanup, new restore_mem (ptr, size));
+    }
+
+private:
+
+  static std::stack<elem> elt_list;
+
+  static std::stack<std::pair <std::string, frame_id_t> > tag_list;
 };
 
-// We could get by without these macros, but they are nice to have...
+// Backward compatibility macros. Avoid them; use protect_var directly.
 
 #define unwind_protect_bool(b) \
-  unwind_protect::save_bool (&(b), (b))
+  unwind_protect::protect_var (b)
 
 #define unwind_protect_int(i) \
-  unwind_protect::save_int (&(i), (i))
+  unwind_protect::protect_var (i)
 
 #define unwind_protect_size_t(i) \
-  unwind_protect::save_size_t (&(i), (i))
+  unwind_protect::protect_var (i)
 
 #define unwind_protect_str(s) \
-  unwind_protect::save_str (&(s), (s))
+  unwind_protect::protect_var (s)
 
 #define unwind_protect_ptr(p) \
-  unwind_protect::save_ptr (reinterpret_cast<void **> (&(p)), \
-                            reinterpret_cast<void *> (p))
+  unwind_protect::protect_var (p)
 
 #define unwind_protect_fptr(p) \
-  unwind_protect::save_ptr (reinterpret_cast<void **> (&(p)), \
-                            FCN_PTR_CAST (void *, p))
+  unwind_protect::protect_var (p)
 
 #define unwind_protect_const_ptr(p) \
-  unwind_protect::save_ptr (const_cast<void **> (reinterpret_cast<const void **> (&(p))), \
-                            const_cast<void *> (reinterpret_cast<const void *> (p)))
+  unwind_protect::protect_var (p)
 
 #endif