1 | #pragma once |
2 | |
3 | #include <utility> |
4 | #include <functional> |
5 | |
6 | |
7 | namespace ext |
8 | { |
9 | template <class F> |
10 | class [[nodiscard]] basic_scope_guard |
11 | { |
12 | public: |
13 | constexpr basic_scope_guard() = default; |
14 | constexpr basic_scope_guard(basic_scope_guard && src) : function{std::exchange(src.function, F{})} {} |
15 | |
16 | constexpr basic_scope_guard & operator=(basic_scope_guard && src) |
17 | { |
18 | if (this != &src) |
19 | { |
20 | invoke(); |
21 | function = std::exchange(src.function, F{}); |
22 | } |
23 | return *this; |
24 | } |
25 | |
26 | template <typename G, typename = std::enable_if_t<std::is_convertible_v<G, F>, void>> |
27 | constexpr basic_scope_guard(const G & function_) : function{function_} {} |
28 | |
29 | template <typename G, typename = std::enable_if_t<std::is_convertible_v<G, F>, void>> |
30 | constexpr basic_scope_guard(G && function_) : function{std::move(function_)} {} |
31 | |
32 | ~basic_scope_guard() { invoke(); } |
33 | |
34 | private: |
35 | void invoke() |
36 | { |
37 | if constexpr (std::is_constructible_v<bool, F>) |
38 | { |
39 | if (!function) |
40 | return; |
41 | } |
42 | |
43 | function(); |
44 | } |
45 | |
46 | F function = F{}; |
47 | }; |
48 | |
49 | using scope_guard = basic_scope_guard<std::function<void(void)>>; |
50 | |
51 | |
52 | template <class F> |
53 | inline basic_scope_guard<F> make_scope_guard(F && function_) { return std::forward<F>(function_); } |
54 | } |
55 | |
56 | #define SCOPE_EXIT_CONCAT(n, ...) \ |
57 | const auto scope_exit##n = ext::make_scope_guard([&] { __VA_ARGS__; }) |
58 | #define SCOPE_EXIT_FWD(n, ...) SCOPE_EXIT_CONCAT(n, __VA_ARGS__) |
59 | #define SCOPE_EXIT(...) SCOPE_EXIT_FWD(__LINE__, __VA_ARGS__) |
60 | |
61 | |