GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
unwind-prot.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1993-2024 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 
39 
40 class
43 {
44 public:
45 
46  unwind_protect () : m_lifo () { }
47 
48  OCTAVE_DISABLE_COPY_MOVE (unwind_protect)
49 
50  // Destructor should not raise an exception, so all actions
51  // registered should be exception-safe. If you're not sure, see
52  // unwind_protect_safe.
53 
54  ~unwind_protect () { run (); }
55 
56  operator bool () const { return ! empty (); }
57 
58  void run_first ()
59  {
60  if (! empty ())
61  {
62  // No leak on exception!
63  std::unique_ptr<elem> ptr (m_lifo.top ());
64  m_lifo.pop ();
65  ptr->run ();
66  }
67  }
68 
69  void discard_first ()
70  {
71  if (! empty ())
72  {
73  elem *ptr = m_lifo.top ();
74  m_lifo.pop ();
75  delete ptr;
76  }
77  }
78 
79  std::size_t size () const { return m_lifo.size (); }
80 
81 protected:
82 
83  virtual void add_action (elem *new_elem)
84  {
85  m_lifo.push (new_elem);
86  }
87 
88  std::stack<elem *> m_lifo;
89 };
90 
91 // Like unwind_protect, but this one will guard against the possibility
92 // of seeing an exception (or interrupt) in the cleanup actions.
93 // Not that we can do much about it, but at least we won't crash.
94 
95 class
98 {
99 private:
100 
101  void warn_unhandled_exception () const;
102 
103 public:
104 
106 
107  OCTAVE_DISABLE_COPY_MOVE (unwind_protect_safe)
108 
110  {
111  while (! empty ())
112  {
113  try
114  {
115  run_first ();
116  }
117  catch (...) // Yes, the black hole. Remember we're in a destructor.
118  {
119  warn_unhandled_exception ();
120  }
121  }
122  }
123 };
124 
125 // In most cases, the following are preferred for efficiency. Some
126 // cases may require the flexibility of the general unwind_protect
127 // mechanism defined above.
128 
129 // Perform action at end of the current scope when unwind_action
130 // object destructor is called.
131 //
132 // For example:
133 //
134 // void fcn (int val) { ... }
135 //
136 // ...
137 //
138 // {
139 // int val = 42;
140 //
141 // // template parameters, std::bind and std::function provide
142 // // flexibility in calling forms (function pointer or lambda):
143 //
144 // unwind_action act1 (fcn, val);
145 // unwind_action act2 ([val] () { fcn (val); });
146 // }
147 //
148 // NOTE: Don't forget to provide a name for the unwind_action
149 // variable. If you write
150 //
151 // unwind_action /* NO NAME! */ (...);
152 //
153 // then the destructor for the temporary anonymous object will be
154 // called immediately after the object is constructed instead of at
155 // the end of the current scope.
156 
158 {
159 public:
160 
161  unwind_action () : m_fcn () { }
162 
163  // FIXME: Do we need to apply std::forward to the arguments to
164  // std::bind here?
165 
166  template <typename F, typename... Args>
167  unwind_action (F&& fcn, Args&& ... args)
168  : m_fcn (std::bind (fcn, args...))
169  { }
170 
171  OCTAVE_DISABLE_COPY_MOVE (unwind_action)
172 
173  ~unwind_action () { run (); }
174 
175  // FIXME: Do we need to apply std::forward to the arguments to
176  // std::bind here?
177 
178  template <typename F, typename... Args>
179  void set (F&& fcn, Args&& ... args)
180  {
181  m_fcn = std::bind (fcn, args...);
182  }
183 
184  void set () { m_fcn = nullptr; }
185 
186  // Alias for set() which is clearer about programmer intention.
187  void discard () { set (); }
188 
189  void run ()
190  {
191  if (m_fcn)
192  m_fcn ();
193 
194  // Invalidate so action won't run again when object is deleted.
195  discard ();
196  }
197 
198 private:
199 
200  std::function<void ()> m_fcn;
201 };
202 
203 // Like unwind_action, but this one will guard against the possibility
204 // of seeing an exception (or interrupt) in the cleanup actions.
205 // Not that we can do much about it, but at least we won't crash.
206 
208 {
209 private:
210 
211  void warn_unhandled_exception () const;
212 
213 public:
214 
215  unwind_action_safe () : m_fcn () { }
216 
217  // FIXME: Do we need to apply std::forward to the arguments to
218  // std::bind here?
219 
220  template <typename F, typename... Args>
221  unwind_action_safe (F&& fcn, Args&& ... args)
222  : m_fcn (std::bind (fcn, args...))
223  { }
224 
225  OCTAVE_DISABLE_COPY_MOVE (unwind_action_safe)
226 
227  ~unwind_action_safe () { run (); }
228 
229  // FIXME: Do we need to apply std::forward to the arguments to
230  // std::bind here?
231 
232  template <typename F, typename... Args>
233  void set (F&& fcn, Args&& ... args)
234  {
235  m_fcn = std::bind (fcn, args...);
236  }
237 
238  void set () { m_fcn = nullptr; }
239 
240  // Alias for set() which is clearer about programmer intention.
241  void discard () { set (); }
242 
243  void run ()
244  {
245  try
246  {
247  if (m_fcn)
248  m_fcn ();
249  }
250  catch (...) // Yes, the black hole. Remember we're in a destructor.
251  {
252  warn_unhandled_exception ();
253  }
254 
255  // Invalidate so action won't run again when object is deleted.
256  discard ();
257  }
258 
259 private:
260 
261  std::function<void ()> m_fcn;
262 };
263 
264 // Reset a variable value at the end of the current scope when
265 // unwind_protect_var object destructor is called.
266 //
267 // For example:
268 //
269 // {
270 // int x = 42;
271 // unwind_protect_var<int> upv (x); // X will be reset at end of scope
272 // x = 13; // Set temporary value.
273 // }
274 //
275 // Temporary value may be set at construction:
276 //
277 // {
278 // int x = ...;
279 // unwind_protect_var<int> upv (x, 13); // X will be reset.
280 // // temporary value is 13.
281 // }
282 //
283 // NOTE: Don't forget to provide a name for the unwind_protect_var
284 // variable. If you write
285 //
286 // unwind_protect_var<type> /* NO NAME! */ (...);
287 //
288 // then the destructor for the temporary anonymous object will be
289 // called immediately after the object is constructed instead of at
290 // the end of the current scope.
291 //
292 // FIXME: Once we are able to use C++17, class template argument
293 // deduction will allow us to omit the explicit template type from the
294 // constructor expression:
295 //
296 // unwind_protect_var upv (...);
297 
298 template <typename T>
300 {
301 public:
302 
303  // Ensure that the value referenced by REF will be reset when this
304  // unwind_protect_var object goes out of scope.
305 
306  explicit unwind_protect_var (T& ref)
307  : m_ref (ref), m_val (ref)
308  { }
309 
310  // Set the value referenced by REF to NEW_VAL and ensure that it
311  // will be reset to its original value when this
312  // unwind_protect_var object goes out of scope.
313 
314  unwind_protect_var (T& ref, const T& new_val)
315  : m_ref (ref), m_val (ref)
316  {
317  m_ref = new_val;
318  }
319 
320  OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE (unwind_protect_var)
321 
323  {
324  m_ref = m_val;
325  }
326 
327 private:
328 
329  T& m_ref;
330  T m_val;
331 };
332 
333 OCTAVE_END_NAMESPACE(octave)
334 
335 #endif
unwind_action_safe(F &&fcn, Args &&... args)
Definition: unwind-prot.h:221
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:233
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:179
void discard()
Definition: unwind-prot.h:187
unwind_action(F &&fcn, Args &&... args)
Definition: unwind-prot.h:167
unwind_protect_var(T &ref, const T &new_val)
Definition: unwind-prot.h:314
unwind_protect_var(T &ref)
Definition: unwind-prot.h:306
virtual void add_action(elem *new_elem)
Definition: unwind-prot.h:83
std::size_t size() const
Definition: unwind-prot.h:79
void discard_first()
Definition: unwind-prot.h:69
void run_first()
Definition: unwind-prot.h:58
std::stack< elem * > m_lifo
Definition: unwind-prot.h:88
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define OCTAVE_API
Definition: main.cc:55