GNU Octave  8.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-2023 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 (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 
58  ~unwind_protect (void) { run (); }
59 
60  operator bool (void) const { return ! empty (); }
61 
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 
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 
83  std::size_t size (void) const { return m_lifo.size (); }
84 
85 protected:
86 
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
102 {
103 private:
104 
105  void warn_unhandled_exception (void) const;
106 
107 public:
108 
110 
111  // No copying!
112 
114 
115  unwind_protect_safe& operator = (const unwind_protect_safe&) = delete;
116 
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 (function pointer or lambda):
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 
166 {
167 public:
168 
169  unwind_action (void) : m_fcn () { }
170 
171  // FIXME: Do we need to apply std::forward to the arguments to
172  // std::bind here?
173 
174  template <typename F, typename... Args>
175  unwind_action (F&& fcn, Args&& ... args)
176  : m_fcn (std::bind (fcn, args...))
177  { }
178 
179  // No copying!
180 
181  unwind_action (const unwind_action&) = delete;
182 
183  unwind_action& operator = (const unwind_action&) = delete;
184 
185  ~unwind_action (void) { run (); }
186 
187  // FIXME: Do we need to apply std::forward to the arguments to
188  // std::bind here?
189 
190  template <typename F, typename... Args>
191  void set (F&& fcn, Args&& ... args)
192  {
193  m_fcn = std::bind (fcn, args...);
194  }
195 
196  void set (void) { m_fcn = nullptr; }
197 
198  // Alias for set() which is clearer about programmer intention.
199  void discard (void) { set (); }
200 
201  void run (void)
202  {
203  if (m_fcn)
204  m_fcn ();
205 
206  // Invalidate so action won't run again when object is deleted.
207  discard ();
208  }
209 
210 private:
211 
212  std::function<void (void)> m_fcn;
213 };
214 
215 // Like unwind_action, but this one will guard against the possibility
216 // of seeing an exception (or interrupt) in the cleanup actions.
217 // Not that we can do much about it, but at least we won't crash.
218 
220 {
221 private:
222 
223  void warn_unhandled_exception (void) const;
224 
225 public:
226 
227  unwind_action_safe (void) : m_fcn () { }
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  unwind_action_safe (F&& fcn, Args&& ... args)
234  : m_fcn (std::bind (fcn, args...))
235  { }
236 
237  // No copying!
238 
240 
241  unwind_action_safe& operator = (const unwind_action_safe&) = delete;
242 
243  ~unwind_action_safe (void) { run (); }
244 
245  // FIXME: Do we need to apply std::forward to the arguments to
246  // std::bind here?
247 
248  template <typename F, typename... Args>
249  void set (F&& fcn, Args&& ... args)
250  {
251  m_fcn = std::bind (fcn, args...);
252  }
253 
254  void set (void) { m_fcn = nullptr; }
255 
256  // Alias for set() which is clearer about programmer intention.
257  void discard (void) { set (); }
258 
259  void run (void)
260  {
261  try
262  {
263  if (m_fcn)
264  m_fcn ();
265  }
266  catch (...) // Yes, the black hole. Remember we're in a destructor.
267  {
268  warn_unhandled_exception ();
269  }
270 
271  // Invalidate so action won't run again when object is deleted.
272  discard ();
273  }
274 
275 private:
276 
277  std::function<void (void)> m_fcn;
278 };
279 
280 // Reset a variable value at the end of the current scope when
281 // unwind_protect_var object destructor is called.
282 //
283 // For example:
284 //
285 // {
286 // int x = 42;
287 // unwind_protect_var<int> upv (x); // X will be reset at end of scope
288 // x = 13; // Set temporary value.
289 // }
290 //
291 // Temporary value may be set at construction:
292 //
293 // {
294 // int x = ...;
295 // unwind_protect_var<int> upv (x, 13); // X will be reset.
296 // // temporary value is 13.
297 // }
298 //
299 // NOTE: Don't forget to provide a name for the unwind_protect_var
300 // variable. If you write
301 //
302 // unwind_protect_var<type> /* NO NAME! */ (...);
303 //
304 // then the destructor for the temporary anonymous object will be
305 // called immediately after the object is constructed instead of at
306 // the end of the current scope.
307 //
308 // FIXME: Once we are able to use C++17, class template argument
309 // deduction will allow us to omit the explicit template type from the
310 // constructor expression:
311 //
312 // unwind_protect_var upv (...);
313 
314 template <typename T>
316 {
317 public:
318 
319  // Ensure that the value referenced by REF will be reset when this
320  // unwind_protect_var object goes out of scope.
321 
322  explicit unwind_protect_var (T& ref)
323  : m_ref (ref), m_val (ref)
324  { }
325 
326  // Set the value referenced by REF to NEW_VAL and ensure that it
327  // will be reset to its original value when this
328  // unwind_protect_var object goes out of scope.
329 
330  unwind_protect_var (T& ref, const T& new_val)
331  : m_ref (ref), m_val (ref)
332  {
333  m_ref = new_val;
334  }
335 
336  // No copying!
337 
339 
341 
343  {
344  m_ref = m_val;
345  }
346 
347 private:
348 
349  T& m_ref;
350  T m_val;
351 };
352 
354 
355 #endif
OCTAVE_END_NAMESPACE(octave)
std::function< void(void)> m_fcn
Definition: unwind-prot.h:277
void discard(void)
Definition: unwind-prot.h:257
unwind_action_safe(F &&fcn, Args &&... args)
Definition: unwind-prot.h:233
unwind_action_safe(const unwind_action_safe &)=delete
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:249
unwind_action(const unwind_action &)=delete
~unwind_action(void)
Definition: unwind-prot.h:185
void run(void)
Definition: unwind-prot.h:201
void discard(void)
Definition: unwind-prot.h:199
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:191
unwind_action(void)
Definition: unwind-prot.h:169
void set(void)
Definition: unwind-prot.h:196
unwind_action(F &&fcn, Args &&... args)
Definition: unwind-prot.h:175
std::function< void(void)> m_fcn
Definition: unwind-prot.h:212
unwind_protect_safe(const unwind_protect_safe &)=delete
unwind_protect_var(const unwind_protect_var &)=delete
unwind_protect_var & operator=(const unwind_protect_var &)=delete
unwind_protect_var(T &ref, const T &new_val)
Definition: unwind-prot.h:330
unwind_protect_var(T &ref)
Definition: unwind-prot.h:322
void run_first(void)
Definition: unwind-prot.h:62
std::size_t size(void) const
Definition: unwind-prot.h:83
unwind_protect(void)
Definition: unwind-prot.h:46
virtual void add_action(elem *new_elem)
Definition: unwind-prot.h:87
~unwind_protect(void)
Definition: unwind-prot.h:58
unwind_protect(const unwind_protect &)=delete
void discard_first(void)
Definition: unwind-prot.h:73
std::stack< elem * > m_lifo
Definition: unwind-prot.h:92
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define OCTAVE_API
Definition: main.in.cc:55