header_utils
Loading...
Searching...
No Matches
scope.h
1
4
5#pragma once
6
7#include <type_traits>
8
9namespace ghassanpl
10{
11
13 template <class EF>
15 {
16 template <class EFP>
17 explicit scope_guard(EFP&& f) noexcept(noexcept(EFP(std::forward<EFP>(f))))
18 : exit_function(std::forward<EFP>(f))
19 {
20 }
21
22 scope_guard(scope_guard&& rhs) noexcept(noexcept(EF(std::move(rhs.exit_function))))
23 : exit_function(std::move(rhs.exit_function))
24 {
25 rhs.release();
26 }
27
28 scope_guard(const scope_guard&) = delete;
29 scope_guard& operator=(const scope_guard&) = delete;
30 scope_guard& operator=(scope_guard&&) = delete;
31
32 ~scope_guard() noexcept(noexcept(this->exit_function()))
33 {
34 if (this->execute_on_destruction)
35 this->exit_function();
36 }
37
38 void release() noexcept
39 {
40 this->execute_on_destruction = false;
41 }
42
43 bool will_execute_on_destruction() const noexcept
44 {
45 return this->execute_on_destruction;
46 }
47
48 private:
49
50 EF exit_function;
51 bool execute_on_destruction{ true };
52 };
53
55 template <class EF>
57 {
58 template <class EFP>
59 explicit counted_scope_guard(EFP&& f, int initial_count = 0) noexcept(noexcept(EFP(std::forward<EFP>(f))))
60 : m_exit_function(std::forward<EFP>(f))
61 , m_count(initial_count)
62 {
63 }
64
65 counted_scope_guard(counted_scope_guard&& rhs) noexcept(noexcept(EF(std::move(rhs.m_exit_function))))
66 : m_exit_function(std::move(rhs.m_exit_function))
67 , m_count(std::exchange(rhs.m_count, 0))
68 {
69 }
70
72 counted_scope_guard& operator=(const counted_scope_guard&) = delete;
73 counted_scope_guard& operator=(counted_scope_guard&&) = delete;
74
77 {
78 if (m_count > 0)
79 m_exit_function();
80 }
81
84 {
85 ++m_count;
86 }
87
90 {
91 if (m_count > 0)
92 --m_count;
93 }
94
97 {
98 m_count = 0;
99 }
100
101 bool will_execute_on_destruction() const noexcept
102 {
103 return m_count > 0;
104 }
105
106 private:
107
108 EF m_exit_function;
109 int m_count = 0;
110 };
111
112 template <class EF>
113 scope_guard(EF) -> scope_guard<EF>;
114
117 template <class R, class D>
119 {
120 unique_resource() = default;
121
122 template <class RR, class DD>
123 unique_resource(RR&& r, DD&& d) noexcept(std::is_nothrow_constructible_v<R1, RR> && std::is_nothrow_constructible_v<D, DD>)
124 : resource(std::forward<RR>(r))
125 , deleter(std::forward<DD>(d))
126 , execute_on_reset(true)
127 {
128 }
129
130 template <class RR, class DD, class I = std::decay_t<RR>>
131 unique_resource(RR&& r, const I& invalid, DD&& d) noexcept(std::is_nothrow_constructible_v<R1, RR> && std::is_nothrow_constructible_v<D, DD>)
132 : resource(std::forward<RR>(r))
133 , deleter(std::forward<DD>(d))
134 , execute_on_reset(!bool(resource == invalid))
135 {
136 }
137
138 unique_resource(unique_resource&& rhs) noexcept(std::is_nothrow_move_constructible_v<R1> && std::is_nothrow_move_constructible_v<D>)
139 : resource(std::move(rhs.resource))
140 , deleter(std::move(rhs.deleter))
141 , execute_on_reset(std::exchange(rhs.execute_on_reset, false))
142 {
143 }
144
145 ~unique_resource() noexcept(noexcept(deleter(resource)))
146 {
147 if (execute_on_reset)
148 deleter(resource);
149 }
150
151 unique_resource& operator=(unique_resource&& rhs) noexcept(std::is_nothrow_move_assignable_v<R1> && std::is_nothrow_move_assignable_v<D> && noexcept(deleter(resource)))
152 {
153 if (std::addressof(rhs) == this)
154 return *this;
155
156 reset();
157 if constexpr (std::is_nothrow_move_assignable_v<R1>)
158 {
159 if constexpr (std::is_nothrow_move_assignable_v<D>)
160 {
161 resource = std::move(rhs.resource);
162 deleter = std::move(rhs.deleter);
163 }
164 else
165 {
166 deleter = rhs.deleter;
167 resource = std::move(rhs.resource);
168 }
169 }
170 else
171 {
172 if constexpr (std::is_nothrow_move_assignable_v<D>)
173 {
174 resource = rhs.resource;
175 deleter = std::move(rhs.deleter);
176 }
177 else
178 {
179 resource = rhs.resource;
180 deleter = rhs.deleter;
181 }
182 }
183 execute_on_reset = std::exchange(rhs.execute_on_reset, false);
184 return *this;
185 }
186
187 void reset() noexcept(noexcept(deleter(resource)))
188 {
189 if (execute_on_reset)
190 {
191 execute_on_reset = false;
192 deleter(resource);
193 }
194 }
195
196 template <class RR>
197 void reset(RR&& r) noexcept(noexcept(deleter(resource)) && std::is_nothrow_assignable_v<R1&, RR>)
198 {
199 if (std::addressof(r) == std::addressof(resource))
200 return;
201
202 reset();
203 try
204 {
205 if constexpr (std::is_nothrow_assignable_v<R1&, RR>)
206 resource = std::forward<RR>(r);
207 else
208 resource = std::as_const(r);
209 }
210 catch (...)
211 {
212 deleter(r);
213 throw;
214 }
215 execute_on_reset = true;
216 }
217
218 void release() noexcept
219 {
220 execute_on_reset = false;
221 }
222
223 const R& get() const noexcept
224 {
225 return resource;
226 }
227
228 auto operator*() const noexcept
229 requires std::is_pointer_v<R> && (!std::is_void_v<std::remove_pointer_t<R>>)
230 {
231 return *get();
232 }
233
234 R operator->() const noexcept
235 requires std::is_pointer_v<R>
236 {
237 return get();
238 }
239
240 const D& get_deleter() const noexcept { return deleter; }
241
242 private:
243
244 using R1 = std::conditional_t<std::is_reference_v<R>, std::reference_wrapper<std::remove_reference_t<R>>, R>;
245 R1 resource{};
246 D deleter{};
247 bool execute_on_reset{};
248 };
249
250 template<class R, class D>
252 template <class R, class D, class I = std::decay_t<R>>
254
257 template <typename T, bool OPTIONAL = false>
259 {
260 template <typename U>
261 scoped_value_change(T& ref, U new_val) noexcept(std::is_nothrow_move_constructible_v<T>)
262 requires (!OPTIONAL)
263 : m_ref(std::addressof(ref))
264 , m_original_value(std::exchange(ref, new_val))
265 {
266 }
267
268 template <typename U>
269 scoped_value_change(T& ref, U new_val) noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_copy_constructible_v<T>)
270 requires OPTIONAL
271 : m_ref(std::addressof(ref))
272 , m_original_value(*m_ref != new_val ? std::exchange(ref, new_val) : ref)
273 {
274 }
275
276 ~scoped_value_change() noexcept(std::is_nothrow_move_assignable_v<T>)
277 {
278 revert();
279 }
280
282 scoped_value_change(scoped_value_change&& other) noexcept(std::is_nothrow_move_constructible_v<T>)
283 : m_ref(other.m_ref)
284 , m_original_value(std::move(other.m_original_value))
285 {
286 other.m_ref = nullptr;
287 }
288
289 scoped_value_change& operator=(const scoped_value_change&) = delete;
290
294
295 /*
296 scoped_value_change& operator=(scoped_value_change&& other) noexcept(std::is_nothrow_move_assignable_v<T>)
297 {
298 revert();
299
300 m_ref = other.m_ref;
301 m_original_value = std::move(other.m_original_value);
302 other.m_ref = nullptr;
303 return *this;
304 }
305 */
306
307 bool valid() const noexcept { return m_ref != nullptr; }
308
312 {
313 return m_original_value;
314 }
315
318 T original_value() && noexcept(std::is_nothrow_move_constructible_v<T>)
319 {
320 return std::move(m_original_value);
321 }
322
325 T const& current_value()
326 {
327 return *m_ref;
328 }
329
333 {
334 if (m_ref)
335 {
336 auto& ref = *m_ref;
337 m_ref = nullptr;
338
339 if constexpr (OPTIONAL)
340 {
341 if (ref == m_original_value)
342 return;
343 }
344
345 ref = std::move(m_original_value);
346 }
347 }
348
354 {
355 auto& ref = *m_ref;
356 m_ref = nullptr;
357
358 if constexpr (OPTIONAL)
359 {
360 if (ref != m_original_value)
361 return std::move(m_original_value);
362 }
363
364 return std::exchange(ref, std::move(m_original_value));
365 }
366
370 {
371 m_ref = nullptr;
372 }
373
378 {
379 m_ref = nullptr;
380 return std::move(m_original_value);
381 }
382
383 private:
384
385 T* m_ref;
386 T m_original_value;
387 };
388
389 template <typename T>
390 using optional_scoped_value_change = scoped_value_change<T, true>;
391
392 template <typename T, typename U>
393 scoped_value_change(T&, U&&) -> scoped_value_change<T>;
394
396
398 template <typename T>
400 {
401 scope_counter(T& ref) noexcept(noexcept(++ref))
402 : m_ref(std::addressof(ref))
403 {
404 ++ref;
405 }
406
407 scope_counter(const scope_counter&) = delete;
409 {
410 m_ref = std::exchange(other.m_ref, nullptr);
411 }
412 scope_counter& operator=(const scope_counter&) = delete;
413 scope_counter& operator=(scope_counter&&) = delete;
414
415 bool valid() const noexcept { return m_ref != nullptr; }
416
417 ~scope_counter() noexcept(noexcept(--m_ref))
418 {
419 if (m_ref)
420 --m_ref;
421 }
422
423 void release() const noexcept
424 {
425 m_ref = nullptr;
426 }
427
428 private:
429
430 T* m_ref;
431 };
432
433
434}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
Primary namespace for everything in this library.
Definition align+rec2.h:10
A RAII class that executes a function on destruction, if its request counter is greater than zero.
Definition scope.h:57
void unrequest() noexcept
Decrements the request counter.
Definition scope.h:89
~counted_scope_guard() noexcept(noexcept(m_exit_function()))
Executes the function on destruction if the request counter is greater than zero.
Definition scope.h:76
void request() noexcept
Increments the request counter.
Definition scope.h:83
void release() noexcept
Releases the guard, so that it will not execute the function on destruction.
Definition scope.h:96
TODO: atomic_scoped_value_change.
Definition scope.h:400
A RAII class that executes a function on destruction.
Definition scope.h:15
A RAII class that changes the value of a variable and reverts it to the original value on destruction...
Definition scope.h:259
void revert() noexcept(std::is_nothrow_move_assignable_v< T >)
Reverts the value to the original one.
Definition scope.h:332
T original_value() &&noexcept(std::is_nothrow_move_constructible_v< T >)
Returns the original value.
Definition scope.h:318
T release_and_return() noexcept(std::is_nothrow_move_constructible_v< T >)
Causes the value to not be reverted on destruction.
Definition scope.h:377
void release() noexcept
Causes the value to not be reverted on destruction.
Definition scope.h:369
T const & current_value()
Returns the current value.
Definition scope.h:325
T const & original_value() const &noexcept
Returns the original value.
Definition scope.h:311
T revert_and_return() noexcept(std::is_nothrow_move_assignable_v< T > &&std::is_nothrow_move_constructible_v< T >)
Reverts the value to the original one.
Definition scope.h:353
scoped_value_change & operator=(scoped_value_change &&other)=delete
Move assignment is not implemented because it's not clear and obvious what the order of reversions wo...
An equivalent to unique_ptr for values that are not heap pointers.
Definition scope.h:119