halcheck 1.0
Loading...
Searching...
No Matches
scope.hpp
1#ifndef HALCHECK_LIB_SCOPE_HPP
2#define HALCHECK_LIB_SCOPE_HPP
3
10#include <halcheck/lib/functional.hpp>
11#include <halcheck/lib/optional.hpp>
12#include <halcheck/lib/type_traits.hpp>
13#include <halcheck/lib/utility.hpp>
14
15#include <cstddef>
16#include <type_traits>
17
18namespace halcheck { namespace lib {
19
25template<typename F = lib::move_only_function<void() &&>>
26class finally_t {
27public:
28 static_assert(lib::is_invocable<F &&>(), "F && should be invocable");
29
30// TODO: fix check on MSVC
31#ifndef _MSC_VER
32 static_assert(std::is_nothrow_move_constructible<F>(), "F should be nothrow move constructible");
33#endif
34
35 template<typename G>
36 friend class finally_t;
37
41 constexpr finally_t() = default;
42
47 constexpr explicit finally_t(F func) noexcept(std::is_nothrow_move_constructible<F>())
48 : _func(lib::in_place, std::move(func)) {}
49
58 finally_t(finally_t &&other) noexcept(std::is_nothrow_move_constructible<F>()) : _func(std::move(other._func)) {
59 other._func.reset();
60 }
61
67 template<typename G, HALCHECK_REQUIRE(std::is_convertible<G, F>())>
68 finally_t(finally_t<G> &&other) noexcept(std::is_constructible<F, G>()) // NOLINT: implicit conversion
69 : _func(std::move(other._func)) {
70 other._func.reset();
71 }
72
78 template<typename G, HALCHECK_REQUIRE(!std::is_convertible<G, F>()), HALCHECK_REQUIRE(std::is_constructible<F, G>())>
79 explicit finally_t(finally_t<G> &&other) noexcept(std::is_constructible<F, G>()) : _func(std::move(other._func)) {
80 other._func.reset();
81 }
82
83 finally_t(const finally_t &) = delete;
84 finally_t &operator=(const finally_t &) = delete;
85 finally_t &operator=(finally_t &&) = delete;
86 void *operator new(std::size_t) = delete;
87 void *operator new[](std::size_t) = delete;
88
92 ~finally_t() noexcept {
93 if (_func)
94 lib::invoke(std::move(*_func));
95 }
96
97private:
98 template<typename G>
99 struct combine {
100 lib::optional<F> first;
101 lib::optional<G> second;
102
103 void operator()() {
104 if (second)
105 lib::invoke(std::move(*second));
106 if (first)
107 lib::invoke(std::move(*first));
108 }
109 };
110
111 template<typename G>
112 finally_t<combine<G>> make_combined(finally_t<G> &&other) && {
113 if (!_func && !other._func)
114 return finally_t<combine<G>>();
115
116 combine<G> func{std::move(_func), std::move(other._func)};
117 _func.reset();
118 other._func.reset();
119 return finally_t<combine<G>>(std::move(func));
120 }
121
132 template<typename G>
134 return std::move(lhs).make_combined(std::move(rhs));
135 }
136
137 lib::optional<F> _func;
138};
139
156template<typename F, HALCHECK_REQUIRE(lib::is_invocable<F>())>
157lib::finally_t<F> finally(F func) {
158 return lib::finally_t<F>(std::move(func));
159}
160
161}} // namespace halcheck::lib
162
163#endif
constexpr finally_t(F func) noexcept(std::is_nothrow_move_constructible< F >())
Construct an object that calls the given function upon destruction.
Definition scope.hpp:47
finally_t(finally_t &&other) noexcept(std::is_nothrow_move_constructible< F >())
Delays the invocation of a finally_t's underlying function by transfering the responsibility of calli...
Definition scope.hpp:58
friend finally_t< combine< G > > operator+(finally_t &&lhs, finally_t< G > &&rhs)
Combines two finally_t values into one, such that both underlying functions are called upon destructi...
Definition scope.hpp:133
finally_t(finally_t< G > &&other) noexcept(std::is_constructible< F, G >())
Delays the invocation of a finally_t's underlying function by transfering the responsibility of calli...
Definition scope.hpp:68
Calls a function upon destruction.
Definition scope.hpp:26
constexpr finally_t()=default
A default-constructed finally_t does nothing upon scope exit.
~finally_t() noexcept
Invokes the underlying function.
Definition scope.hpp:92
An implementation of std::optional.
Definition optional.hpp:338
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@20 invoke
An implementation of std::invoke.
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
static constexpr in_place_t in_place
An implementation of std::in_place.
Definition utility.hpp:33
STL namespace.
An implementation of std::is_invocable.
Definition invoke.hpp:66