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