libUTL++
ScopeGuard.h
1 #pragma once
2 
4 // This code is based on an excellent talk by Andrei Alexandrescu at CppCon 2015. //
6 
7 UTL_NS_BEGIN;
8 
10 
22 #define SCOPE_EXIT \
23  auto UTL_ANONYMOUS_VARIABLE(scopeExit) = utl::ScopeExitMacroHelper() + [&]() noexcept
24 
26 
38 #define SCOPE_FAIL \
39  auto UTL_ANONYMOUS_VARIABLE(scopeFail) = utl::ScopeFailMacroHelper() + [&]() noexcept
40 
42 
54 #define SCOPE_SUCCESS \
55  auto UTL_ANONYMOUS_VARIABLE(scopeSuccess) = utl::ScopeSuccessMacroHelper() + [&]() noexcept
56 
58 
59 class ScopeGuardImplBase
60 {
61 public:
62  void
63  dismiss() const
64  {
65  _dismissed = true;
66  }
67 
68 protected:
69  ScopeGuardImplBase()
70  : _dismissed(false)
71  {
72  }
73 
74  ~ScopeGuardImplBase()
75  {
76  }
77 
78 protected:
79  mutable bool _dismissed;
80 
81 private:
82  // Disable assignment
83  ScopeGuardImplBase& operator=(const ScopeGuardImplBase&);
84 };
85 
87 
88 template <typename Callable>
89 class ScopeGuardExit : public ScopeGuardImplBase
90 {
91 public:
92  explicit ScopeGuardExit(const Callable& callable)
93  : _callable(callable)
94  {
95  }
96 
97  explicit ScopeGuardExit(Callable&& callable)
98  : _callable(std::move(callable))
99  {
100  }
101 
102  ~ScopeGuardExit() noexcept
103  {
104  if (_dismissed) return;
105  _callable();
106  }
107 
108 private:
109  Callable _callable;
110 };
111 
113 
114 // TODO: use std::uncaught_exceptions when gcc supports it
115 class UncaughtExceptionCounter
116 {
117 public:
118  UncaughtExceptionCounter()
119  : _exceptionCount(std::uncaught_exceptions())
120  {
121  }
122 
123  bool
124  isNewUncaughtException() noexcept
125  {
126  return std::uncaught_exceptions() > _exceptionCount;
127  }
128 
129 private:
130  int getUncaughtExceptionCount() noexcept;
131 
132 private:
133  int _exceptionCount;
134 };
135 
137 
138 template <typename Callable, bool executeOnException>
139 class ScopeGuardForNewException : public ScopeGuardImplBase
140 {
141 public:
142  explicit ScopeGuardForNewException(const Callable& callable)
143  : _callable(callable)
144  {
145  }
146 
147  explicit ScopeGuardForNewException(Callable&& callable)
148  : _callable(std::move(callable))
149  {
150  }
151 
152  ~ScopeGuardForNewException() noexcept
153  {
154  if (executeOnException == _ec.isNewUncaughtException())
155  {
156  if (_dismissed) return;
157  _callable();
158  }
159  }
160 
161 private:
162  Callable _callable;
163  UncaughtExceptionCounter _ec;
164 };
165 
167 
168 enum class ScopeExitMacroHelper
169 {
170 };
171 
172 enum class ScopeFailMacroHelper
173 {
174 };
175 
176 enum class ScopeSuccessMacroHelper
177 {
178 };
179 
181 
182 template <typename Callable>
183 ScopeGuardExit<Callable>
184 makeExitGuard(Callable&& callable)
185 {
186  return ScopeGuardExit<Callable>(std::forward(callable));
187 }
188 
189 template <typename Callable>
190 ScopeGuardForNewException<Callable, true>
191 makeFailureGuard(Callable&& callable)
192 {
193  return ScopeGuardForNewException<Callable, true>(std::forward(callable));
194 }
195 
196 template <typename Callable>
197 ScopeGuardForNewException<Callable, false>
198 makeSuccessGuard(Callable&& callable)
199 {
200  return ScopeGuardForNewException<Callable, false>(std::forward(callable));
201 }
202 
204 
205 UTL_NS_END;
206 
208 
209 template <typename Callable>
210 utl::ScopeGuardExit<Callable> operator+(utl::ScopeExitMacroHelper, Callable&& callable)
211 {
212  return utl::ScopeGuardExit<Callable>(std::forward<Callable>(callable));
213 }
214 
215 template <typename Callable>
216 utl::ScopeGuardForNewException<Callable, true> operator+(utl::ScopeFailMacroHelper,
217  Callable&& callable)
218 {
219  return utl::ScopeGuardForNewException<typename std::decay<Callable>::type, true>(
220  std::forward<Callable>(callable));
221 }
222 
223 template <typename Callable>
224 utl::ScopeGuardForNewException<Callable, false> operator+(utl::ScopeSuccessMacroHelper,
225  Callable&& callable)
226 {
227  return utl::ScopeGuardForNewException<typename std::decay<Callable>::type, false>(
228  std::forward<Callable>(callable));
229 }