Skip to content

Commit 5a25908

Browse files
add release funcitonality
1 parent 77a2e23 commit 5a25908

File tree

2 files changed

+246
-51
lines changed

2 files changed

+246
-51
lines changed

include/beman/scope/scope.hpp

Lines changed: 117 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace beman::scope {
3636
// private:
3737
// EF exit_function; // exposition only
3838
// bool execute_on_destruction{true}; // exposition only
39-
// int uncaught_on_creation{uncaught_exceptions()}; // exposition only
39+
// int m_uncaught_on_creation{uncaught_exceptions()}; // exposition only
4040
// };
4141
//
4242
// template <class EF>
@@ -45,61 +45,91 @@ namespace beman::scope {
4545

4646
//=========================================================
4747

48+
template <typename T>
49+
concept HasCanInvoke = requires(T t) {
50+
{ t.can_invoke() } -> std::convertible_to<bool>;
51+
};
52+
53+
template <typename T>
54+
concept HasStaticCanInvoke = requires {
55+
{ T::can_invoke() } -> std::convertible_to<bool>;
56+
};
57+
58+
template <typename T>
59+
concept HasRelease = requires(T t) {
60+
{ t.release() } -> std::same_as<void>;
61+
};
62+
63+
template <typename T>
64+
concept HasStaticRelease = requires {
65+
{ T::release() } -> std::same_as<void>;
66+
};
67+
4868
template <typename F, typename R, typename... Args>
4969
concept invocable_return = std::invocable<F, Args...> && std::same_as<std::invoke_result_t<F, Args...>, R>;
5070

71+
template <typename T>
72+
concept scope_invoke_checker = HasStaticCanInvoke<T> || HasCanInvoke<T> || invocable_return<T, bool>;
73+
5174
//=========================================================
5275

5376
struct ExecuteAlways;
5477

5578
//=========================================================
5679

57-
template <invocable_return<void> ExitFunc, invocable_return<bool> ExecuteCondition = ExecuteAlways>
58-
class scope_guard {
80+
template <invocable_return<void> ExitFunc, scope_invoke_checker InvokeChecker = ExecuteAlways>
81+
class scope_guard : public InvokeChecker {
5982
public:
60-
explicit scope_guard(ExitFunc&& func) /*noexcept(see below)*/
61-
: m_exit_func(std::move(func)) //
83+
explicit scope_guard(ExitFunc&& exit_func) /*noexcept(see below)*/
84+
: m_exit_func(std::move(exit_func)) //
85+
{}
86+
87+
explicit scope_guard(ExitFunc&& exit_func, InvokeChecker&& invoke_checker) /*noexcept(see below)*/
88+
: m_exit_func(std::move(exit_func)),
89+
m_invoke_checker{std::move(invoke_checker)} //
6290
{}
6391

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)} {}
92+
explicit scope_guard(scope_guard&& rhs) noexcept
93+
: m_exit_func{std::move(rhs)},
94+
m_invoke_checker{std::move(rhs.m_invoke_checker)} //
95+
{}
6696

6797
scope_guard(const scope_guard&) = delete;
6898
scope_guard& operator=(const scope_guard&) = delete;
6999
scope_guard& operator=(scope_guard&&) = delete;
70100

71101
~scope_guard() /*noexcept(see below)*/ {
72-
if (can_invoke_check(m_invoke_condition_func)) {
102+
if (can_invoke_check(m_invoke_checker)) {
73103
m_exit_func();
74104
}
75105
}
76106

77-
void release() noexcept {
78-
// Needs implementation
107+
void release() noexcept
108+
requires HasRelease<InvokeChecker> || HasStaticRelease<InvokeChecker>
109+
{
110+
if constexpr (HasRelease<InvokeChecker>) {
111+
m_invoke_checker.release();
112+
} else {
113+
InvokeChecker::release();
114+
}
79115
}
80116

81117
private:
82-
ExitFunc m_exit_func;
83-
[[no_unique_address]] ExecuteCondition m_invoke_condition_func;
118+
ExitFunc m_exit_func;
119+
[[no_unique_address]] InvokeChecker m_invoke_checker;
84120

85121
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-
}) {
122+
static bool can_invoke_check(const T& obj) {
123+
if constexpr (HasStaticCanInvoke<T>) {
90124
return T::can_invoke();
91-
} else if constexpr (requires(T t) {
92-
{ t.can_invoke() } -> std::convertible_to<bool>;
93-
}) {
125+
} else if constexpr (HasCanInvoke<T>) {
94126
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();
127+
} else if constexpr (invocable_return<T, bool>) {
128+
return std::invoke(obj);
129+
//} else if constexpr (HasStaticParenthesisOperator<T>) {
130+
// return T::operator()();
131+
//} else if constexpr (HasParenthesisOperator<T>) {
132+
// return obj();
103133
} else {
104134
return true; // Default behavior if no check function is available
105135
}
@@ -109,54 +139,90 @@ class scope_guard {
109139
//=========================================================
110140

111141
template <std::invocable ExitFunc>
112-
scope_guard(ExitFunc) -> scope_guard<ExitFunc>;
113-
114-
//=========================================================
142+
scope_guard(ExitFunc&&) -> scope_guard<ExitFunc>;
115143

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;
144+
template <std::invocable ExitFunc, scope_invoke_checker InvokeChecker>
145+
scope_guard(ExitFunc&&, InvokeChecker&&) -> scope_guard<ExitFunc, InvokeChecker>;
127146

147+
//=========================================================
148+
//=========================================================
128149
//=========================================================
129150

130151
struct ExecuteAlways {
131-
[[nodiscard]] constexpr bool operator()() const { return true; }
152+
[[nodiscard]] static constexpr bool can_invoke() { return true; }
153+
};
154+
155+
class ExecuteWhenNoException {
156+
public:
157+
[[nodiscard]] bool can_invoke() const { return m_uncaught_on_creation >= std::uncaught_exceptions(); }
158+
159+
private:
160+
int m_uncaught_on_creation = std::uncaught_exceptions();
132161
};
133162

134-
struct ExecuteWhenNoException {
163+
class ExecuteOnlyWhenException {
164+
public:
165+
[[nodiscard]] bool can_invoke() const { return m_uncaught_on_creation < std::uncaught_exceptions(); }
135166

136-
[[nodiscard]] bool operator()() const { return uncaught_on_creation >= std::uncaught_exceptions(); }
167+
private:
168+
int m_uncaught_on_creation = std::uncaught_exceptions();
169+
};
170+
171+
//=========================================================
172+
173+
template <typename T = void>
174+
class Releasable;
175+
176+
template <>
177+
class Releasable<void> {
178+
public:
179+
bool can_invoke() const { return m_can_invoke; }
180+
181+
void release() { m_can_invoke = false; }
137182

138183
private:
139-
int uncaught_on_creation = std::uncaught_exceptions();
184+
bool m_can_invoke = true;
140185
};
141186

142-
struct ExecuteOnlyWhenException {
187+
template <scope_invoke_checker InvokeChecker>
188+
class Releasable<InvokeChecker> : private InvokeChecker {
189+
public:
190+
Releasable() = default;
191+
192+
Releasable(InvokeChecker&& invoke_checker) : InvokeChecker(std::move(invoke_checker)) {}
143193

144-
[[nodiscard]] bool operator()() const { return uncaught_on_creation < std::uncaught_exceptions(); }
194+
bool can_invoke() const { return m_can_invoke && static_cast<const InvokeChecker*>(this)->can_invoke(); }
195+
196+
void release() { m_can_invoke = false; }
145197

146198
private:
147-
int uncaught_on_creation = std::uncaught_exceptions();
199+
bool m_can_invoke = true;
148200
};
149201

150202
//=========================================================
151203

204+
// -- 7.5.1 Header <scope> synopsis [scope.syn] --
205+
//
206+
// namespace std {
207+
// template <class EF>
208+
// class scope_exit;
209+
//
210+
// template <class EF>
211+
// class scope_fail;
212+
//
213+
// template <class EF>
214+
// class scope_success;
215+
216+
//=========================================================
217+
152218
template <class ExitFunc>
153-
using scope_exit = scope_guard<ExitFunc>;
219+
using scope_exit = scope_guard<ExitFunc, Releasable<>>;
154220

155221
template <class ExitFunc>
156-
using scope_success = scope_guard<ExitFunc, ExecuteWhenNoException>;
222+
using scope_success = scope_guard<ExitFunc, Releasable<ExecuteWhenNoException>>;
157223

158224
template <class ExitFunc>
159-
using scope_fail = scope_guard<ExitFunc, ExecuteOnlyWhenException>;
225+
using scope_fail = scope_guard<ExitFunc, Releasable<ExecuteOnlyWhenException>>;
160226

161227
//=========================================================
162228

0 commit comments

Comments
 (0)