changeset 15397:1054ab58cd58

abstract unwind_protect * action-container.h: New file. Provide action_container base class. * event-queue.h: New file. Provide event_queue class. * unwind-prot.h: Derive unwind_protect from action_container.
author John W. Eaton <jwe@octave.org>
date Mon, 17 Sep 2012 19:52:20 -0400
parents 7a009eea571a
children 231d8d3b8225
files libinterp/interp-core/action-container.h libinterp/interp-core/event-queue.h libinterp/interp-core/unwind-prot.cc libinterp/interp-core/unwind-prot.h
diffstat 4 files changed, 529 insertions(+), 266 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/action-container.h
@@ -0,0 +1,342 @@
+/*
+
+Copyright (C) 1993-2012 John W. Eaton
+Copyright (C) 2009-2010 VZLU Prague
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_action_container_h)
+#define octave_action_container_h 1
+
+// This class allows registering actions in a list for later
+// execution, either explicitly or when the container goes out of
+// scope.
+
+// FIXME -- is there a better name for this class?
+
+class
+OCTINTERP_API
+action_container
+{
+public:
+
+  // A generic unwind_protect element. Knows how to run itself and
+  // discard itself.  Also, contains a pointer to the next element.
+  class elem
+  {
+  public:
+    elem (void) { }
+
+    virtual void run (void) { }
+
+    virtual ~elem (void) { }
+
+    friend class action_container;
+
+  private:
+
+    // No copying!
+
+    elem (const elem&);
+
+    elem& operator = (const elem&);
+  };
+
+  // An element that merely runs a void (*)(void) function.
+
+  class fcn_elem : public elem
+  {
+  public:
+    fcn_elem (void (*fptr) (void))
+      : e_fptr (fptr) { }
+
+    void run (void) { e_fptr (); }
+
+  private:
+    void (*e_fptr) (void);
+  };
+
+  // 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 fcn_arg_elem : public elem
+  {
+  public:
+    fcn_arg_elem (void (*fcn) (T), T arg)
+      : e_fcn (fcn), e_arg (arg) { }
+
+    void run (void) { e_fcn (e_arg); }
+
+  private:
+
+    // No copying!
+
+    fcn_arg_elem (const fcn_arg_elem&);
+
+    fcn_arg_elem& operator = (const fcn_arg_elem&);
+
+    void (*e_fcn) (T);
+    T e_arg;
+  };
+
+  // An element that stores a variable of type T along with a
+  // void (*) (const T&) function pointer, and calls the function with
+  // the parameter.
+
+  template <class T>
+  class fcn_crefarg_elem : public elem
+  {
+  public:
+    fcn_crefarg_elem (void (*fcn) (const T&), const T& arg)
+      : e_fcn (fcn), e_arg (arg) { }
+
+    void run (void) { e_fcn (e_arg); }
+
+  private:
+    void (*e_fcn) (const T&);
+    T e_arg;
+  };
+
+  // An element for calling a member function.
+
+  template <class T>
+  class method_elem : public elem
+  {
+  public:
+    method_elem (T *obj, void (T::*method) (void))
+      : e_obj (obj), e_method (method) { }
+
+    void run (void) { (e_obj->*e_method) (); }
+
+  private:
+
+    T *e_obj;
+    void (T::*e_method) (void);
+
+    // No copying!
+
+    method_elem (const method_elem&);
+
+    method_elem operator = (const method_elem&);
+  };
+
+  // An element for calling a member function with a single argument
+
+  template <class T, class A>
+  class method_arg_elem : public elem
+  {
+  public:
+    method_arg_elem (T *obj, void (T::*method) (A), A arg)
+      : e_obj (obj), e_method (method), e_arg (arg) { }
+
+    void run (void) { (e_obj->*e_method) (e_arg); }
+
+  private:
+
+    T *e_obj;
+    void (T::*e_method) (A);
+    A e_arg;
+
+    // No copying!
+
+    method_arg_elem (const method_arg_elem&);
+
+    method_arg_elem operator = (const method_arg_elem&);
+  };
+
+  // An element for calling a member function with a single argument
+
+  template <class T, class A>
+  class method_crefarg_elem : public elem
+  {
+  public:
+    method_crefarg_elem (T *obj, void (T::*method) (const A&), const A& arg)
+      : e_obj (obj), e_method (method), e_arg (arg) { }
+
+    void run (void) { (e_obj->*e_method) (e_arg); }
+
+  private:
+
+    T *e_obj;
+    void (T::*e_method) (const A&);
+    A e_arg;
+
+    // No copying!
+
+    method_crefarg_elem (const method_crefarg_elem&);
+
+    method_crefarg_elem operator = (const method_crefarg_elem&);
+  };
+
+  // An element that stores arbitrary variable, and restores it.
+
+  template <class T>
+  class restore_var_elem : public elem
+  {
+  public:
+    restore_var_elem (T& ref, const T& val)
+      : e_ptr (&ref), e_val (val) { }
+
+    void run (void) { *e_ptr = e_val; }
+
+  private:
+
+    // No copying!
+
+    restore_var_elem (const restore_var_elem&);
+
+    restore_var_elem& operator = (const restore_var_elem&);
+
+    T *e_ptr, e_val;
+  };
+
+  // Deletes a class allocated using new.
+
+  template <class T>
+  class delete_ptr_elem : public elem
+  {
+  public:
+    delete_ptr_elem (T *ptr)
+      : e_ptr (ptr) { }
+
+    void run (void) { delete e_ptr; }
+
+  private:
+
+    T *e_ptr;
+
+    // No copying!
+
+    delete_ptr_elem (const delete_ptr_elem&);
+
+    delete_ptr_elem operator = (const delete_ptr_elem&);
+  };
+
+  action_container (void) { }
+
+  virtual ~action_container (void) { }
+
+  virtual void add (elem *new_elem) = 0;
+
+  // Call to void func (void).
+  void add_fcn (void (*fcn) (void))
+  {
+    add (new fcn_elem (fcn));
+  }
+
+  // Call to void func (T).
+  template <class T>
+  void add_fcn (void (*action) (T), T val)
+  {
+    add (new fcn_arg_elem<T> (action, val));
+  }
+
+  // Call to void func (const T&).
+  template <class T>
+  void add_fcn (void (*action) (const T&), const T& val)
+  {
+    add (new fcn_crefarg_elem<T> (action, val));
+  }
+
+  // Call to T::method (void).
+  template <class T>
+  void add_method (T *obj, void (T::*method) (void))
+  {
+    add (new method_elem<T> (obj, method));
+  }
+
+  // Call to T::method (A).
+  template <class T, class A>
+  void add_method (T *obj, void (T::*method) (A), A arg)
+  {
+    add (new method_arg_elem<T, A> (obj, method, arg));
+  }
+
+  // Call to T::method (const A&).
+  template <class T, class A>
+  void add_method (T *obj, void (T::*method) (const A&), const A& arg)
+  {
+    add (new method_crefarg_elem<T, A> (obj, method, arg));
+  }
+
+  // Call to delete (T*).
+
+  template <class T>
+  void add_delete (T *obj)
+  {
+    add (new delete_ptr_elem<T> (obj));
+  }
+
+  // Protect any variable.
+  template <class T>
+  void protect_var (T& var)
+  {
+    add (new restore_var_elem<T> (var, var));
+  }
+
+  // Protect any variable, value given.
+  template <class T>
+  void protect_var (T& var, const T& val)
+  {
+    add (new restore_var_elem<T> (var, val));
+  }
+
+  operator bool (void) const { return ! empty (); }
+
+  virtual void run_first (void) = 0;
+
+  void run (size_t num)
+  {
+    if (num > size ())
+      num = size ();
+
+    for (size_t i = 0; i < num; i++)
+      run_first ();
+  }
+
+  void run (void) { run (size ()); }
+
+  virtual void discard_first (void) = 0;
+
+  void discard (size_t num)
+  {
+    if (num > size ())
+      num = size ();
+
+    for (size_t i = 0; i < num; i++)
+      discard_first ();
+  }
+
+  void discard (void) { discard (size ()); }
+
+  virtual size_t size (void) const = 0;
+
+  bool empty (void) const { return size () == 0; }
+
+private:
+
+  // No copying!
+
+  action_container (const action_container&);
+
+  action_container& operator = (const action_container&);
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/libinterp/interp-core/event-queue.h
@@ -0,0 +1,126 @@
+/*
+
+Copyright (C) 2012 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_event_queue_h)
+#define octave_event_queue_h 1
+
+#include <queue>
+#include <memory>
+
+#include "action-container.h"
+
+class
+OCTINTERP_API
+event_queue : public action_container
+{
+public:
+
+  event_queue (void) : fifo () { }
+
+  // Destructor should not raise an exception, so all actions
+  // registered should be exception-safe (but setting error_state is
+  // allowed). If you're not sure, see event_queue_safe.
+
+  ~event_queue (void) { run (); }
+
+  void add (elem *new_elem)
+  {
+    fifo.push (new_elem);
+  }
+
+  void run_first (void)
+  {
+    if (! empty ())
+      {
+        // No leak on exception!
+        std::auto_ptr<elem> ptr (fifo.front ());
+        fifo.pop ();
+        ptr->run ();
+      }
+  }
+
+  void discard_first (void)
+  {
+    if (! empty ())
+      {
+        elem *ptr = fifo.front ();
+        fifo.pop ();
+        delete ptr;
+      }
+  }
+
+  size_t size (void) const { return fifo.size (); }
+
+protected:
+
+  std::queue<elem *> fifo;
+
+private:
+
+  // No copying!
+
+  event_queue (const event_queue&);
+
+  event_queue& operator = (const event_queue&);
+};
+
+// Like event_queue, but this one will guard against the
+// possibility of seeing an exception (or interrupt) in the cleanup
+// actions. Not that we can do much about it, but at least we won't
+// crash.
+
+class
+event_queue_safe : public event_queue
+{
+private:
+
+  static void gripe_exception (void);
+
+public:
+
+  event_queue_safe (void) : event_queue () { }
+
+  ~event_queue_safe (void)
+    {
+      while (! empty ())
+        {
+          try
+            {
+              run_first ();
+            }
+          catch (...) // Yes, the black hole. Remember we're in a dtor.
+            {
+              gripe_exception ();
+            }
+        }
+    }
+
+private:
+
+  // No copying!
+
+  event_queue_safe (const event_queue_safe&);
+
+  event_queue_safe& operator = (const event_queue_safe&);
+};
+
+#endif
--- a/libinterp/interp-core/unwind-prot.cc
+++ b/libinterp/interp-core/unwind-prot.cc
@@ -25,12 +25,8 @@
 #include <config.h>
 #endif
 
-#include <cstddef>
-#include <cstring>
-
 #include "error.h"
 #include "unwind-prot.h"
-#include "utils.h"
 
 void unwind_protect_safe::gripe_exception (void)
 {
--- a/libinterp/interp-core/unwind-prot.h
+++ b/libinterp/interp-core/unwind-prot.h
@@ -24,289 +24,74 @@
 #if !defined (octave_unwind_prot_h)
 #define octave_unwind_prot_h 1
 
-#include <cstddef>
-
-#include <string>
+#include <stack>
 #include <memory>
 
-// This class allows registering cleanup actions.
+#include "action-container.h"
+
 class
 OCTINTERP_API
-unwind_protect
+unwind_protect : public action_container
 {
 public:
 
-  // A generic unwind_protect element. Knows how to run itself and discard itself.
-  // Also, contains a pointer to the next element.
-  class elem
-  {
-    elem *next;
-
-  public:
-    elem (void) : next (0) { }
-
-    virtual void run (void) { }
-
-    virtual ~elem (void) { }
-
-    friend class unwind_protect;
-
-  private:
-
-    // No copying!
-
-    elem (const elem&);
-
-    elem& operator = (const elem&);
-  };
-
-  // An element that merely runs a void (*)(void) function.
-
-  class fcn_elem : public elem
-  {
-  public:
-    fcn_elem (void (*fptr) (void))
-      : e_fptr (fptr) { }
+  unwind_protect (void) : lifo () { }
 
-    void run (void) { e_fptr (); }
-
-  private:
-    void (*e_fptr) (void);
-  };
-
-  // 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 fcn_arg_elem : public elem
-  {
-  public:
-    fcn_arg_elem (void (*fcn) (T), T arg)
-      : e_fcn (fcn), e_arg (arg) { }
+  // Destructor should not raise an exception, so all actions
+  // registered should be exception-safe (but setting error_state is
+  // allowed). If you're not sure, see unwind_protect_safe.
 
-    void run (void) { e_fcn (e_arg); }
-
-  private:
-
-    // No copying!
-
-    fcn_arg_elem (const fcn_arg_elem&);
-
-    fcn_arg_elem& operator = (const fcn_arg_elem&);
-
-    void (*e_fcn) (T);
-    T e_arg;
-  };
-
-  // An element that stores a variable of type T along with a void (*) (const T&)
-  // function pointer, and calls the function with the parameter.
+  ~unwind_protect (void) { run (); }
 
-  template <class T>
-  class fcn_crefarg_elem : public elem
+  virtual void add (elem *new_elem)
   {
-  public:
-    fcn_crefarg_elem (void (*fcn) (const T&), T arg)
-      : e_fcn (fcn), e_arg (arg) { }
-
-    void run (void) { e_fcn (e_arg); }
-
-  private:
-    void (*e_fcn) (const T&);
-    T e_arg;
-  };
-
-  // An element for calling a member function.
-
-  template <class T>
-  class method_elem : public elem
-  {
-  public:
-    method_elem (T *obj, void (T::*method) (void))
-      : e_obj (obj), e_method (method) { }
-
-    void run (void) { (e_obj->*e_method) (); }
-
-  private:
-
-    T *e_obj;
-    void (T::*e_method) (void);
-
-    // No copying!
-
-    method_elem (const method_elem&);
+    lifo.push (new_elem);
+  }
 
-    method_elem operator = (const method_elem&);
-  };
-
-  // An element that stores arbitrary variable, and restores it.
-
-  template <class T>
-  class restore_var_elem : public elem
+  void add (void (*fcn) (void *), void *ptr = 0) GCC_ATTR_DEPRECATED
   {
-  public:
-    restore_var_elem (T& ref, const T& val)
-      : e_ptr (&ref), e_val (val) { }
-
-    void run (void) { *e_ptr = e_val; }
-
-  private:
+    add (new fcn_arg_elem<void *> (fcn, ptr));
+  }
 
-    // No copying!
-
-    restore_var_elem (const restore_var_elem&);
-
-    restore_var_elem& operator = (const restore_var_elem&);
-
-    T *e_ptr, e_val;
-  };
+  operator bool (void) const { return ! empty (); }
 
-  // Deletes a class allocated using new.
-
-  template <class T>
-  class delete_ptr_elem : public elem
-  {
-  public:
-    delete_ptr_elem (T *ptr)
-      : e_ptr (ptr) { }
+  void run_top (void) GCC_ATTR_DEPRECATED { run_first (); }
 
-    void run (void) { delete e_ptr; }
-
-  private:
-
-    T *e_ptr;
-
-    // No copying!
-
-    delete_ptr_elem (const delete_ptr_elem&);
-
-    delete_ptr_elem operator = (const delete_ptr_elem&);
-  };
-
-  unwind_protect (void) : head () { }
-
-  void add (elem *new_elem)
-    {
-      new_elem->next = head;
-      head = new_elem;
-    }
-
-  // For backward compatibility.
-  void add (void (*fcn) (void *), void *ptr = 0)
-    {
-      add (new fcn_arg_elem<void *> (fcn, ptr));
-    }
+  void run_first (void)
+  {
+    if (! empty ())
+      {
+        // No leak on exception!
+        std::auto_ptr<elem> ptr (lifo.top ());
+        lifo.pop ();
+        ptr->run ();
+      }
+  }
 
-  // Call to void func (void).
-  void add_fcn (void (*fcn) (void))
-    {
-      add (new fcn_elem (fcn));
-    }
-
-  // Call to void func (T).
-  template <class T>
-  void add_fcn (void (*action) (T), T val)
-    {
-      add (new fcn_arg_elem<T> (action, val));
-    }
+  void run_top (int num) GCC_ATTR_DEPRECATED { run (num); }
 
-  // Call to void func (const T&).
-  template <class T>
-  void add_fcn (void (*action) (const T&), T val)
-    {
-      add (new fcn_crefarg_elem<T> (action, val));
-    }
-
-  // Call to T::method (void).
-  template <class T>
-  void add_method (T *obj, void (T::*method) (void))
-    {
-      add (new method_elem<T> (obj, method));
-    }
-
-  // Call to delete (T*).
-
-  template <class T>
-  void add_delete (T *obj)
-    {
-      add (new delete_ptr_elem<T> (obj));
-    }
+  void discard_top (void) GCC_ATTR_DEPRECATED { discard_first (); }
 
-  // Protect any variable.
-  template <class T>
-  void protect_var (T& var)
-    {
-      add (new restore_var_elem<T> (var, var));
-    }
-
-  // Protect any variable, value given.
-  template <class T>
-  void protect_var (T& var, const T& val)
-    {
-      add (new restore_var_elem<T> (var, val));
-    }
-
-  operator bool (void) const
-    {
-      return head != 0;
-    }
-
-  void run_top (void)
-    {
-      if (head)
-        {
-          // No leak on exception!
-          std::auto_ptr<elem> ptr (head);
-          head = ptr->next;
-          ptr->run ();
-        }
-    }
-
-  void run_top (int num)
-    {
-      while (num-- > 0)
-        run_top ();
-    }
+  void discard_first (void)
+  {
+    if (! empty ())
+      {
+        elem *ptr = lifo.top ();
+        lifo.pop ();
+        delete ptr;
+      }
+  }
 
-  void discard_top (void)
-    {
-      if (head)
-        {
-          elem *ptr = head;
-          head = ptr->next;
-          delete ptr;
-        }
-    }
+  void discard_top (int num) GCC_ATTR_DEPRECATED { discard (num); }
 
-  void discard_top (int num)
-    {
-      while (num-- > 0)
-        discard_top ();
-    }
+  size_t size (void) const { return lifo.size (); }
 
-  void run (void)
-    {
-      while (head)
-        run_top ();
-    }
+protected:
 
-  void discard (void)
-    {
-      while (head)
-        discard_top ();
-    }
-
-  // Destructor should not raise an exception, so all actions registered should
-  // be exception-safe (but setting error_state is allowed). If you're not sure,
-  // see unwind_protect_safe.
-  ~unwind_protect (void)
-    {
-      run ();
-    }
+  std::stack<elem *> lifo;
 
 private:
 
-  elem *head;
-
   // No copying!
 
   unwind_protect (const unwind_protect&);
@@ -314,24 +99,30 @@
   unwind_protect& operator = (const unwind_protect&);
 };
 
-// Like unwind_protect, but this one will guard against the possibility of seeing
-// an exception (or interrupt) in the cleanup actions. Not that we can do much about
-// it, but at least we won't crash.
+// Like unwind_protect, but this one will guard against the
+// possibility of seeing an exception (or interrupt) in the cleanup
+// actions. Not that we can do much about it, but at least we won't
+// crash.
 
 class
 OCTINTERP_API
 unwind_protect_safe : public unwind_protect
 {
+private:
+
   static void gripe_exception (void);
 
 public:
+
+  unwind_protect_safe (void) : unwind_protect () { }
+
   ~unwind_protect_safe (void)
     {
-      while (*this)
+      while (! empty ())
         {
           try
             {
-              run_top ();
+              run_first ();
             }
           catch (...) // Yes, the black hole. Remember we're in a dtor.
             {
@@ -339,6 +130,14 @@
             }
         }
     }
+
+private:
+
+  // No copying!
+
+  unwind_protect_safe (const unwind_protect_safe&);
+
+  unwind_protect_safe& operator = (const unwind_protect_safe&);
 };
 
 #endif