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