GNU Octave 7.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-2022 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
38namespace octave
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
351 };
352}
353
354#endif
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:249
unwind_action_safe(const unwind_action_safe &)=delete
std::function< void(void)> m_fcn
Definition: unwind-prot.h:277
unwind_action_safe(F &&fcn, Args &&... args)
Definition: unwind-prot.h:233
std::function< void(void)> m_fcn
Definition: unwind-prot.h:212
unwind_action(F &&fcn, Args &&... args)
Definition: unwind-prot.h:175
void set(F &&fcn, Args &&... args)
Definition: unwind-prot.h:191
unwind_action(const unwind_action &)=delete
unwind_protect_safe(const unwind_protect_safe &)=delete
unwind_protect_var(T &ref, const T &new_val)
Definition: unwind-prot.h:330
unwind_protect_var & operator=(const unwind_protect_var &)=delete
unwind_protect_var(const unwind_protect_var &)=delete
void discard_first(void)
Definition: unwind-prot.h:73
unwind_protect(const unwind_protect &)=delete
std::size_t size(void) const
Definition: unwind-prot.h:83
virtual void add_action(elem *new_elem)
Definition: unwind-prot.h:87
std::stack< elem * > m_lifo
Definition: unwind-prot.h:92
#define OCTAVE_API
Definition: main.in.cc:55
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:757
STL namespace.