/** * \file libimp/scope_exit.h * \author mutouyun (orz@orzz.org) * \brief Execute guard function when the enclosing scope exits. */ #pragma once #include // std::forward, std::move #include // std::function #include #include "libipc/imp/detect_plat.h" namespace ipc { template > class scope_exit { F destructor_; mutable bool released_; public: template explicit scope_exit(G &&destructor) noexcept : destructor_(std::forward(destructor)) , released_ (false) {} scope_exit(scope_exit &&other) noexcept : destructor_(std::move(other.destructor_)) , released_ (std::exchange(other.released_, true)) /*release rhs*/ {} scope_exit &operator=(scope_exit &&other) noexcept { destructor_ = std::move(other.destructor_); released_ = std::exchange(other.released_, true); return *this; } ~scope_exit() noexcept { if (!released_) destructor_(); } void release() const noexcept { released_ = true; } void do_exit() noexcept { if (released_) return; destructor_(); released_ = true; } void swap(scope_exit &other) noexcept { std::swap(destructor_, other.destructor_); std::swap(released_ , other.released_); } }; /// \brief Creates a scope_exit object. template auto make_scope_exit(F &&destructor) noexcept { return scope_exit>(std::forward(destructor)); } namespace detail_scope_exit { struct scope_exit_helper { template auto operator=(F &&f) const noexcept { return make_scope_exit(std::forward(f)); } }; } // namespace detail_scope_exit #define LIBIPC_SCOPE_EXIT($VAL) \ LIBIPC_UNUSED auto $VAL = ::ipc::detail_scope_exit::scope_exit_helper{} } // namespace ipc