# HG changeset patch # User John W. Eaton # Date 1347925940 14400 # Node ID 1054ab58cd58531c3f00eb089d32e4ab6a145771 # Parent 7a009eea571aa47113a05199251b24669da450b6 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. diff -r 7a009eea571a -r 1054ab58cd58 libinterp/interp-core/action-container.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/interp-core/action-container.h Mon Sep 17 19:52:20 2012 -0400 @@ -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 +. + +*/ + +#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 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 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 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 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 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 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 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 + void add_fcn (void (*action) (T), T val) + { + add (new fcn_arg_elem (action, val)); + } + + // Call to void func (const T&). + template + void add_fcn (void (*action) (const T&), const T& val) + { + add (new fcn_crefarg_elem (action, val)); + } + + // Call to T::method (void). + template + void add_method (T *obj, void (T::*method) (void)) + { + add (new method_elem (obj, method)); + } + + // Call to T::method (A). + template + void add_method (T *obj, void (T::*method) (A), A arg) + { + add (new method_arg_elem (obj, method, arg)); + } + + // Call to T::method (const A&). + template + void add_method (T *obj, void (T::*method) (const A&), const A& arg) + { + add (new method_crefarg_elem (obj, method, arg)); + } + + // Call to delete (T*). + + template + void add_delete (T *obj) + { + add (new delete_ptr_elem (obj)); + } + + // Protect any variable. + template + void protect_var (T& var) + { + add (new restore_var_elem (var, var)); + } + + // Protect any variable, value given. + template + void protect_var (T& var, const T& val) + { + add (new restore_var_elem (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 diff -r 7a009eea571a -r 1054ab58cd58 libinterp/interp-core/event-queue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/interp-core/event-queue.h Mon Sep 17 19:52:20 2012 -0400 @@ -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 +. + +*/ + +#if !defined (octave_event_queue_h) +#define octave_event_queue_h 1 + +#include +#include + +#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 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 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 diff -r 7a009eea571a -r 1054ab58cd58 libinterp/interp-core/unwind-prot.cc --- a/libinterp/interp-core/unwind-prot.cc Mon Sep 17 08:50:46 2012 -0400 +++ b/libinterp/interp-core/unwind-prot.cc Mon Sep 17 19:52:20 2012 -0400 @@ -25,12 +25,8 @@ #include #endif -#include -#include - #include "error.h" #include "unwind-prot.h" -#include "utils.h" void unwind_protect_safe::gripe_exception (void) { diff -r 7a009eea571a -r 1054ab58cd58 libinterp/interp-core/unwind-prot.h --- 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 - -#include +#include #include -// 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 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 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 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 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 (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 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 (fcn, ptr)); - } + void run_first (void) + { + if (! empty ()) + { + // No leak on exception! + std::auto_ptr 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 - void add_fcn (void (*action) (T), T val) - { - add (new fcn_arg_elem (action, val)); - } + void run_top (int num) GCC_ATTR_DEPRECATED { run (num); } - // Call to void func (const T&). - template - void add_fcn (void (*action) (const T&), T val) - { - add (new fcn_crefarg_elem (action, val)); - } - - // Call to T::method (void). - template - void add_method (T *obj, void (T::*method) (void)) - { - add (new method_elem (obj, method)); - } - - // Call to delete (T*). - - template - void add_delete (T *obj) - { - add (new delete_ptr_elem (obj)); - } + void discard_top (void) GCC_ATTR_DEPRECATED { discard_first (); } - // Protect any variable. - template - void protect_var (T& var) - { - add (new restore_var_elem (var, var)); - } - - // Protect any variable, value given. - template - void protect_var (T& var, const T& val) - { - add (new restore_var_elem (var, val)); - } - - operator bool (void) const - { - return head != 0; - } - - void run_top (void) - { - if (head) - { - // No leak on exception! - std::auto_ptr 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 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