1#pragma once
2
3#include <utility>
4#include <functional>
5
6
7namespace ext
8{
9template <class F>
10class [[nodiscard]] basic_scope_guard
11{
12public:
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
34private:
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
49using scope_guard = basic_scope_guard<std::function<void(void)>>;
50
51
52template <class F>
53inline basic_scope_guard<F> make_scope_guard(F && function_) { return std::forward<F>(function_); }
54}
55
56#define SCOPE_EXIT_CONCAT(n, ...) \
57const 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