GNU Octave  6.2.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-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
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  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
100  OCTAVE_API
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:
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  template <typename F, typename... 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 
179 
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>
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 
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 
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 
246 
248 
250  {
251  m_ref = m_val;
252  }
253 
254  private:
255 
256  T& m_ref;
257  T m_val;
258  };
259 }
260 
261 #endif
std::function< void(void)> m_fcn
Definition: unwind-prot.h:184
unwind_action & operator=(const unwind_action &)=delete
unwind_action(F &&fcn, Args &&... args)
Definition: unwind-prot.h:170
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:237
unwind_protect_var & operator=(const unwind_protect_var &)=delete
unwind_protect_var(const unwind_protect_var &)=delete
size_t size(void) const
Definition: unwind-prot.h:83
void discard_first(void)
Definition: unwind-prot.h:73
unwind_protect(const unwind_protect &)=delete
virtual void add_action(elem *new_elem)
Definition: unwind-prot.h:87
std::stack< elem * > m_lifo
Definition: unwind-prot.h:92