Mercurial > octave
diff libinterp/interp-core/unwind-prot.h @ 15396: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 | 2fc554ffbc28 |
children |
line wrap: on
line diff
--- a/libinterp/interp-core/unwind-prot.h Mon Sep 17 08:50:46 2012 -0400 +++ b/libinterp/interp-core/unwind-prot.h Mon Sep 17 19:52:20 2012 -0400 @@ -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