1 | // Copyright 2019 The Marl Authors. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | // Finally can be used to execute a lambda or function when the final reference |
16 | // to the Finally is dropped. |
17 | // |
18 | // The purpose of a finally is to perform cleanup or termination logic and is |
19 | // especially useful when there are multiple early returns within a function. |
20 | // |
21 | // A moveable Finally can be constructed with marl::make_finally(). |
22 | // A sharable Finally can be constructed with marl::make_shared_finally(). |
23 | |
24 | #ifndef marl_finally_h |
25 | #define marl_finally_h |
26 | |
27 | #include "export.h" |
28 | |
29 | #include <functional> |
30 | #include <memory> |
31 | |
32 | namespace marl { |
33 | |
34 | // Finally is a pure virtual base class, implemented by the templated |
35 | // FinallyImpl. |
36 | class Finally { |
37 | public: |
38 | virtual ~Finally() = default; |
39 | }; |
40 | |
41 | // FinallyImpl implements a Finally. |
42 | // The template parameter F is the function type to be called when the finally |
43 | // is destructed. F must have the signature void(). |
44 | template <typename F> |
45 | class FinallyImpl : public Finally { |
46 | public: |
47 | MARL_NO_EXPORT inline FinallyImpl(const F& func); |
48 | MARL_NO_EXPORT inline FinallyImpl(F&& func); |
49 | MARL_NO_EXPORT inline FinallyImpl(FinallyImpl<F>&& other); |
50 | MARL_NO_EXPORT inline ~FinallyImpl(); |
51 | |
52 | private: |
53 | FinallyImpl(const FinallyImpl<F>& other) = delete; |
54 | FinallyImpl<F>& operator=(const FinallyImpl<F>& other) = delete; |
55 | FinallyImpl<F>& operator=(FinallyImpl<F>&&) = delete; |
56 | F func; |
57 | bool valid = true; |
58 | }; |
59 | |
60 | template <typename F> |
61 | FinallyImpl<F>::FinallyImpl(const F& func) : func(func) {} |
62 | |
63 | template <typename F> |
64 | FinallyImpl<F>::FinallyImpl(F&& func) : func(std::move(func)) {} |
65 | |
66 | template <typename F> |
67 | FinallyImpl<F>::FinallyImpl(FinallyImpl<F>&& other) |
68 | : func(std::move(other.func)) { |
69 | other.valid = false; |
70 | } |
71 | |
72 | template <typename F> |
73 | FinallyImpl<F>::~FinallyImpl() { |
74 | if (valid) { |
75 | func(); |
76 | } |
77 | } |
78 | |
79 | template <typename F> |
80 | inline FinallyImpl<F> make_finally(F&& f) { |
81 | return FinallyImpl<F>(std::forward<F>(f)); |
82 | } |
83 | |
84 | template <typename F> |
85 | inline std::shared_ptr<Finally> make_shared_finally(F&& f) { |
86 | return std::make_shared<FinallyImpl<F>>(std::forward<F>(f)); |
87 | } |
88 | |
89 | } // namespace marl |
90 | |
91 | #endif // marl_finally_h |
92 | |