1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_unwind_prot_h)
27 #define octave_unwind_prot_h 1
28 
29 #include "octave-config.h"
30 
31 #include <cstddef>
32 
33 #include <stack>
34 #include <memory>
35 
36 #include "action-container.h"
37 
38 namespace octave
39 {
40   class
41   OCTAVE_API
42   unwind_protect : public action_container
43   {
44   public:
45 
unwind_protect(void)46     unwind_protect (void) : m_lifo () { }
47 
48     // No copying!
49 
50     unwind_protect (const unwind_protect&) = delete;
51 
52     unwind_protect& operator = (const unwind_protect&) = delete;
53 
54     // Destructor should not raise an exception, so all actions
55     // registered should be exception-safe.  If you're not sure, see
56     // unwind_protect_safe.
57 
~unwind_protect(void)58     ~unwind_protect (void) { run (); }
59 
60     operator bool (void) const { return ! empty (); }
61 
run_first(void)62     void run_first (void)
63     {
64       if (! empty ())
65         {
66           // No leak on exception!
67           std::unique_ptr<elem> ptr (m_lifo.top ());
68           m_lifo.pop ();
69           ptr->run ();
70         }
71     }
72 
discard_first(void)73     void discard_first (void)
74     {
75       if (! empty ())
76         {
77           elem *ptr = m_lifo.top ();
78           m_lifo.pop ();
79           delete ptr;
80         }
81     }
82 
size(void)83     std::size_t size (void) const { return m_lifo.size (); }
84 
85   protected:
86 
add_action(elem * new_elem)87     virtual void add_action (elem *new_elem)
88     {
89       m_lifo.push (new_elem);
90     }
91 
92     std::stack<elem *> m_lifo;
93   };
94 
95   // Like unwind_protect, but this one will guard against the possibility
96   // of seeing an exception (or interrupt) in the cleanup actions.
97   // Not that we can do much about it, but at least we won't crash.
98 
99   class
100   OCTAVE_API
101   unwind_protect_safe : public unwind_protect
102   {
103   private:
104 
105     void warn_unhandled_exception (void) const;
106 
107   public:
108 
unwind_protect_safe(void)109     unwind_protect_safe (void) : unwind_protect () { }
110 
111     // No copying!
112 
113     unwind_protect_safe (const unwind_protect_safe&) = delete;
114 
115     unwind_protect_safe& operator = (const unwind_protect_safe&) = delete;
116 
~unwind_protect_safe(void)117     ~unwind_protect_safe (void)
118     {
119       while (! empty ())
120         {
121           try
122             {
123               run_first ();
124             }
125           catch (...) // Yes, the black hole.  Remember we're in a destructor.
126             {
127               warn_unhandled_exception ();
128             }
129         }
130     }
131   };
132 
133   // In most cases, the following are preferred for efficiency.  Some
134   // cases may require the flexibility of the general unwind_protect
135   // mechanism defined above.
136 
137   // Perform action at end of the current scope when unwind_action
138   // object destructor is called.
139   //
140   // For example:
141   //
142   //   void fcn (int val) { ... }
143   //
144   // ...
145   //
146   //   {
147   //     int val = 42;
148   //
149   //     // template parameters, std::bind and std::function provide
150   //     // flexibility in calling forms:
151   //
152   //     unwind_action act1 (fcn, val);
153   //     unwind_action act2 ([val] (void) { fcn (val); });
154   //   }
155   //
156   // NOTE: Don't forget to provide a name for the unwind_action
157   // variable.  If you write
158   //
159   //   unwind_action /* NO NAME! */ (...);
160   //
161   // then the destructor for the temporary anonymous object will be
162   // called immediately after the object is constructed instead of at
163   // the end of the current scope.
164 
165   class unwind_action
166   {
167   public:
168 
169     template <typename F, typename... Args>
unwind_action(F && fcn,Args &&...args)170     unwind_action (F&& fcn, Args&&... args)
171       : m_fcn (std::bind (fcn, args...))
172     { }
173 
174     // No copying!
175 
176     unwind_action (const unwind_action&) = delete;
177 
178     unwind_action& operator = (const unwind_action&) = delete;
179 
~unwind_action(void)180     ~unwind_action (void) { m_fcn (); }
181 
182   private:
183 
184     std::function<void (void)> m_fcn;
185   };
186 
187   // Reset a variable value at the end of the current scope when
188   // unwind_protect_var object destructor is called.
189   //
190   // For example:
191   //
192   //   {
193   //     int x = 42;
194   //     unwind_protect_var<int> upv (x);  // X will be reset at end of scope
195   //     x = 13;                           // Set temporary value.
196   //   }
197   //
198   // Temporary value may be set at construction:
199   //
200   //   {
201   //     int x = ...;
202   //     unwind_protect_var<int> upv (x, 13);  // X will be reset.
203   //                                           // temporary value is 13.
204   //   }
205   //
206   // NOTE: Don't forget to provide a name for the unwind_protect_var
207   // variable.  If you write
208   //
209   //   unwind_protect_var<type> /* NO NAME! */ (...);
210   //
211   // then the destructor for the temporary anonymous object will be
212   // called immediately after the object is constructed instead of at
213   // the end of the current scope.
214   //
215   // FIXME: Once we are able to use C++17, class template argument
216   // deduction will allow us to omit the explicit template type from the
217   // constructor expression:
218   //
219   //   unwind_protect_var upv (...);
220 
221   template <typename T>
222   class unwind_protect_var
223   {
224   public:
225 
226     // Ensure that the value referenced by REF will be reset when this
227     // unwind_protect_var object goes out of scope.
228 
unwind_protect_var(T & ref)229     explicit unwind_protect_var (T& ref)
230       : m_ref (ref), m_val (ref)
231     { }
232 
233     // Set the value referenced by REF to NEW_VAL and ensure that it
234     // will be reset to its original value when this
235     // unwind_protect_var object goes out of scope.
236 
unwind_protect_var(T & ref,const T & new_val)237     unwind_protect_var (T& ref, const T& new_val)
238       : m_ref (ref), m_val (ref)
239     {
240       m_ref = new_val;
241     }
242 
243     // No copying!
244 
245     unwind_protect_var (const unwind_protect_var&) = delete;
246 
247     unwind_protect_var& operator = (const unwind_protect_var&) = delete;
248 
~unwind_protect_var(void)249     ~unwind_protect_var (void)
250     {
251       m_ref = m_val;
252     }
253 
254   private:
255 
256     T& m_ref;
257     T m_val;
258   };
259 }
260 
261 #endif
262