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 <functional> 28 #include <memory> 29 30 namespace marl { 31 32 // Finally is a pure virtual base class, implemented by the templated 33 // FinallyImpl. 34 class Finally { 35 public: 36 virtual ~Finally() = default; 37 }; 38 39 // FinallyImpl implements a Finally. 40 // The template parameter F is the function type to be called when the finally 41 // is destructed. F must have the signature void(). 42 template <typename F> 43 class FinallyImpl : public Finally { 44 public: 45 inline FinallyImpl(const F& func); 46 inline FinallyImpl(F&& func); 47 inline FinallyImpl(FinallyImpl<F>&& other); 48 inline ~FinallyImpl(); 49 50 private: 51 FinallyImpl(const FinallyImpl<F>& other) = delete; 52 FinallyImpl<F>& operator=(const FinallyImpl<F>& other) = delete; 53 FinallyImpl<F>& operator=(FinallyImpl<F>&&) = delete; 54 F func; 55 bool valid = true; 56 }; 57 58 template <typename F> FinallyImpl(const F & func)59FinallyImpl<F>::FinallyImpl(const F& func) : func(func) {} 60 61 template <typename F> FinallyImpl(F && func)62FinallyImpl<F>::FinallyImpl(F&& func) : func(std::move(func)) {} 63 64 template <typename F> FinallyImpl(FinallyImpl<F> && other)65FinallyImpl<F>::FinallyImpl(FinallyImpl<F>&& other) 66 : func(std::move(other.func)) { 67 other.valid = false; 68 } 69 70 template <typename F> ~FinallyImpl()71FinallyImpl<F>::~FinallyImpl() { 72 if (valid) { 73 func(); 74 } 75 } 76 77 template <typename F> make_finally(F && f)78inline FinallyImpl<F> make_finally(F&& f) { 79 return FinallyImpl<F>(std::move(f)); 80 } 81 82 template <typename F> make_shared_finally(F && f)83inline std::shared_ptr<Finally> make_shared_finally(F&& f) { 84 return std::make_shared<FinallyImpl<F>>(std::move(f)); 85 } 86 87 } // namespace marl 88 89 #endif // marl_finally_h 90