|
3 | 3 | #ifndef BEMAN_SCOPE_HPP |
4 | 4 | #define BEMAN_SCOPE_HPP |
5 | 5 |
|
| 6 | +#include <concepts> |
| 7 | +#include <exception> |
| 8 | + |
6 | 9 | namespace beman::scope { |
7 | 10 |
|
8 | 11 | // -- 7.6.7 Feature test macro -- |
9 | 12 | // |
10 | 13 | // __cpp_lib_scope |
11 | 14 | // |
12 | 15 |
|
13 | | -// -- 7.5.1 Header <scope> synopsis [scope.syn] -- |
14 | | -// |
15 | | -// namespace std { |
16 | | -// template <class EF> |
17 | | -// class scope_exit; |
18 | | -// |
19 | | -// template <class EF> |
20 | | -// class scope_fail; |
21 | | -// |
22 | | -// template <class EF> |
23 | | -// class scope_success; |
24 | | -// |
25 | | -// template <class R, class D> |
26 | | -// class unique_resource; |
27 | | -// |
28 | | -// // factory function |
29 | | -// template <class R, class D, class S = decay_t<R>> |
30 | | -// unique_resource<decay_t<R>, decay_t<D>> |
31 | | -// make_unique_resource_checked(R&& r, const S& invalid, D&& d) noexcept(see below); |
32 | | -// } // namespace std |
33 | | -// |
| 16 | +//========================================================= |
34 | 17 |
|
35 | 18 | // -- 7.5.2 Scope guard class templates [scope.scope_guard] -- |
36 | 19 | // |
@@ -60,6 +43,137 @@ namespace beman::scope { |
60 | 43 | // scope_guard(EF) -> scope_guard<EF>; |
61 | 44 | // |
62 | 45 |
|
| 46 | +//========================================================= |
| 47 | + |
| 48 | +template <typename F, typename R, typename... Args> |
| 49 | +concept invocable_return = std::invocable<F, Args...> && std::same_as<std::invoke_result_t<F, Args...>, R>; |
| 50 | + |
| 51 | +//========================================================= |
| 52 | + |
| 53 | +struct ExecuteAlways; |
| 54 | + |
| 55 | +//========================================================= |
| 56 | + |
| 57 | +template <invocable_return<void> ExitFunc, invocable_return<bool> ExecuteCondition = ExecuteAlways> |
| 58 | +class scope_guard { |
| 59 | + public: |
| 60 | + explicit scope_guard(ExitFunc&& func) /*noexcept(see below)*/ |
| 61 | + : m_exit_func(std::move(func)) // |
| 62 | + {} |
| 63 | + |
| 64 | + scope_guard(scope_guard&& rhs) noexcept |
| 65 | + : m_exit_func{std::move(rhs)}, m_invoke_condition_func{std::move(rhs.m_invoke_condition_func)} {} |
| 66 | + |
| 67 | + scope_guard(const scope_guard&) = delete; |
| 68 | + scope_guard& operator=(const scope_guard&) = delete; |
| 69 | + scope_guard& operator=(scope_guard&&) = delete; |
| 70 | + |
| 71 | + ~scope_guard() /*noexcept(see below)*/ { |
| 72 | + if (can_invoke_check(m_invoke_condition_func)) { |
| 73 | + m_exit_func(); |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + void release() noexcept { |
| 78 | + // Needs implementation |
| 79 | + } |
| 80 | + |
| 81 | + private: |
| 82 | + ExitFunc m_exit_func; |
| 83 | + [[no_unique_address]] ExecuteCondition m_invoke_condition_func; |
| 84 | + |
| 85 | + template <typename T> |
| 86 | + bool can_invoke_check(const T& obj) const { |
| 87 | + if constexpr (requires(T /*t*/) { |
| 88 | + { T::can_invoke() } -> std::convertible_to<bool>; |
| 89 | + }) { |
| 90 | + return T::can_invoke(); |
| 91 | + } else if constexpr (requires(T t) { |
| 92 | + { t.can_invoke() } -> std::convertible_to<bool>; |
| 93 | + }) { |
| 94 | + return obj.can_invoke(); |
| 95 | + } else if constexpr (requires { |
| 96 | + { T::operator()() } -> std::convertible_to<bool>; |
| 97 | + }) { |
| 98 | + return T::operator()(); |
| 99 | + } else if constexpr (requires(T t) { |
| 100 | + { t.operator()() } -> std::convertible_to<bool>; |
| 101 | + }) { |
| 102 | + return obj(); |
| 103 | + } else { |
| 104 | + return true; // Default behavior if no check function is available |
| 105 | + } |
| 106 | + } |
| 107 | +}; |
| 108 | + |
| 109 | +//========================================================= |
| 110 | + |
| 111 | +template <std::invocable ExitFunc> |
| 112 | +scope_guard(ExitFunc) -> scope_guard<ExitFunc>; |
| 113 | + |
| 114 | +//========================================================= |
| 115 | + |
| 116 | +// -- 7.5.1 Header <scope> synopsis [scope.syn] -- |
| 117 | +// |
| 118 | +// namespace std { |
| 119 | +// template <class EF> |
| 120 | +// class scope_exit; |
| 121 | +// |
| 122 | +// template <class EF> |
| 123 | +// class scope_fail; |
| 124 | +// |
| 125 | +// template <class EF> |
| 126 | +// class scope_success; |
| 127 | + |
| 128 | +//========================================================= |
| 129 | + |
| 130 | +struct ExecuteAlways { |
| 131 | + [[nodiscard]] constexpr bool operator()() const { return true; } |
| 132 | +}; |
| 133 | + |
| 134 | +struct ExecuteWhenNoException { |
| 135 | + |
| 136 | + [[nodiscard]] bool operator()() const { return uncaught_on_creation >= std::uncaught_exceptions(); } |
| 137 | + |
| 138 | + private: |
| 139 | + int uncaught_on_creation = std::uncaught_exceptions(); |
| 140 | +}; |
| 141 | + |
| 142 | +struct ExecuteOnlyWhenException { |
| 143 | + |
| 144 | + [[nodiscard]] bool operator()() const { return uncaught_on_creation < std::uncaught_exceptions(); } |
| 145 | + |
| 146 | + private: |
| 147 | + int uncaught_on_creation = std::uncaught_exceptions(); |
| 148 | +}; |
| 149 | + |
| 150 | +//========================================================= |
| 151 | + |
| 152 | +template <class ExitFunc> |
| 153 | +using scope_exit = scope_guard<ExitFunc>; |
| 154 | + |
| 155 | +template <class ExitFunc> |
| 156 | +using scope_success = scope_guard<ExitFunc, ExecuteWhenNoException>; |
| 157 | + |
| 158 | +template <class ExitFunc> |
| 159 | +using scope_fail = scope_guard<ExitFunc, ExecuteOnlyWhenException>; |
| 160 | + |
| 161 | +//========================================================= |
| 162 | + |
| 163 | +// |
| 164 | +// template <class R, class D> |
| 165 | +// class unique_resource; |
| 166 | +// |
| 167 | +// // factory function |
| 168 | +// template <class R, class D, class S = decay_t<R>> |
| 169 | +// unique_resource<decay_t<R>, decay_t<D>> |
| 170 | +// make_unique_resource_checked(R&& r, const S& invalid, D&& d) noexcept(see below); |
| 171 | +// } // namespace std |
| 172 | +// |
| 173 | + |
| 174 | +//========================================================= |
| 175 | + |
| 176 | + |
63 | 177 | // -- 7.6.1 Class template unique_resource [scope.unique_resource.class] -- |
64 | 178 | // |
65 | 179 | // template <class R, class D> |
@@ -93,33 +207,6 @@ namespace beman::scope { |
93 | 207 | // template <typename R, typename D> |
94 | 208 | // unique_resource(R, D) -> unique_resource<R, D>; |
95 | 209 |
|
96 | | -// TODO: Implement |
97 | | -struct scope_exit { |
98 | | - template <typename F> |
99 | | - scope_exit(F) {} |
100 | | - ~scope_exit() { |
101 | | - // TODO: Cleanup |
102 | | - } |
103 | | -}; |
104 | | - |
105 | | -// TODO: Implement |
106 | | -struct scope_fail { |
107 | | - template <typename F> |
108 | | - scope_fail(F) {} |
109 | | - ~scope_fail() { |
110 | | - // TODO: Cleanup |
111 | | - } |
112 | | -}; |
113 | | - |
114 | | -// TODO: Implement |
115 | | -struct scope_success { |
116 | | - template <typename F> |
117 | | - scope_success(F) {} |
118 | | - ~scope_success() { |
119 | | - // TODO: Cleanup |
120 | | - } |
121 | | -}; |
122 | | - |
123 | 210 | } // namespace beman::scope |
124 | 211 |
|
125 | 212 | #endif // BEMAN_SCOPE_HPP |
0 commit comments