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> FinallyImpl(const F & func)61FinallyImpl<F>::FinallyImpl(const F& func) : func(func) {} 62 63 template <typename F> FinallyImpl(F && func)64FinallyImpl<F>::FinallyImpl(F&& func) : func(std::move(func)) {} 65 66 template <typename F> FinallyImpl(FinallyImpl<F> && other)67FinallyImpl<F>::FinallyImpl(FinallyImpl<F>&& other) 68 : func(std::move(other.func)) { 69 other.valid = false; 70 } 71 72 template <typename F> ~FinallyImpl()73FinallyImpl<F>::~FinallyImpl() { 74 if (valid) { 75 func(); 76 } 77 } 78 79 template <typename F> make_finally(F && f)80inline FinallyImpl<F> make_finally(F&& f) { 81 return FinallyImpl<F>(std::forward<F>(f)); 82 } 83 84 template <typename F> make_shared_finally(F && f)85inline 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