|  | /* Copyright (C) 2019-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #ifndef COMMON_SCOPE_EXIT_H | 
|  | #define COMMON_SCOPE_EXIT_H | 
|  |  | 
|  | #include <functional> | 
|  | #include <type_traits> | 
|  | #include "gdbsupport/preprocessor.h" | 
|  |  | 
|  | /* scope_exit is a general-purpose scope guard that calls its exit | 
|  | function at the end of the current scope.  A scope_exit may be | 
|  | canceled by calling the "release" method.  The API is modeled on | 
|  | P0052R5 - Generic Scope Guard and RAII Wrapper for the Standard | 
|  | Library, which is itself based on Andrej Alexandrescu's | 
|  | ScopeGuard/SCOPE_EXIT. | 
|  |  | 
|  | There are two forms available: | 
|  |  | 
|  | - The "make_scope_exit" form allows canceling the scope guard.  Use | 
|  | it like this: | 
|  |  | 
|  | auto cleanup = make_scope_exit ( <function, function object, lambda> ); | 
|  | ... | 
|  | cleanup.release (); // cancel | 
|  |  | 
|  | - If you don't need to cancel the guard, you can use the SCOPE_EXIT | 
|  | macro, like this: | 
|  |  | 
|  | SCOPE_EXIT | 
|  | { | 
|  | // any code you like here. | 
|  | } | 
|  |  | 
|  | See also forward_scope_exit. | 
|  | */ | 
|  |  | 
|  | /* CRTP base class for cancelable scope_exit-like classes.  Implements | 
|  | the common call-custom-function-from-dtor functionality.  Classes | 
|  | that inherit this implement the on_exit() method, which is called | 
|  | from scope_exit_base's dtor.  */ | 
|  |  | 
|  | template <typename CRTP> | 
|  | class scope_exit_base | 
|  | { | 
|  | public: | 
|  | scope_exit_base () = default; | 
|  |  | 
|  | ~scope_exit_base () | 
|  | { | 
|  | if (!m_released) | 
|  | { | 
|  | auto *self = static_cast<CRTP *> (this); | 
|  | self->on_exit (); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* This is needed for make_scope_exit because copy elision isn't | 
|  | guaranteed until C++17.  An optimizing compiler will usually skip | 
|  | calling this, but it must exist.  */ | 
|  | scope_exit_base (const scope_exit_base &other) | 
|  | : m_released (other.m_released) | 
|  | { | 
|  | other.m_released = true; | 
|  | } | 
|  |  | 
|  | void operator= (const scope_exit_base &) = delete; | 
|  |  | 
|  | /* If this is called, then the wrapped function will not be called | 
|  | on destruction.  */ | 
|  | void release () noexcept | 
|  | { | 
|  | m_released = true; | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* True if released.  Mutable because of the copy ctor hack | 
|  | above.  */ | 
|  | mutable bool m_released = false; | 
|  | }; | 
|  |  | 
|  | /* The scope_exit class.  */ | 
|  |  | 
|  | template<typename EF> | 
|  | class scope_exit : public scope_exit_base<scope_exit<EF>> | 
|  | { | 
|  | /* For access to on_exit().  */ | 
|  | friend scope_exit_base<scope_exit<EF>>; | 
|  |  | 
|  | public: | 
|  |  | 
|  | template<typename EFP, | 
|  | typename = gdb::Requires<std::is_constructible<EF, EFP>>> | 
|  | scope_exit (EFP &&f) | 
|  | try : m_exit_function ((!std::is_lvalue_reference<EFP>::value | 
|  | && std::is_nothrow_constructible<EF, EFP>::value) | 
|  | ? std::move (f) | 
|  | : f) | 
|  | { | 
|  | } | 
|  | catch (...) | 
|  | { | 
|  | /* "If the initialization of exit_function throws an exception, | 
|  | calls f()."  */ | 
|  | f (); | 
|  | } | 
|  |  | 
|  | template<typename EFP, | 
|  | typename = gdb::Requires<std::is_constructible<EF, EFP>>> | 
|  | scope_exit (scope_exit &&rhs) | 
|  | noexcept (std::is_nothrow_move_constructible<EF>::value | 
|  | || std::is_nothrow_copy_constructible<EF>::value) | 
|  | : m_exit_function (std::is_nothrow_constructible<EFP>::value | 
|  | ? std::move (rhs) | 
|  | : rhs) | 
|  | { | 
|  | rhs.release (); | 
|  | } | 
|  |  | 
|  | /* This is needed for make_scope_exit because copy elision isn't | 
|  | guaranteed until C++17.  An optimizing compiler will usually skip | 
|  | calling this, but it must exist.  */ | 
|  | scope_exit (const scope_exit &other) | 
|  | : scope_exit_base<scope_exit<EF>> (other), | 
|  | m_exit_function (other.m_exit_function) | 
|  | { | 
|  | } | 
|  |  | 
|  | void operator= (const scope_exit &) = delete; | 
|  | void operator= (scope_exit &&) = delete; | 
|  |  | 
|  | private: | 
|  | void on_exit () | 
|  | { | 
|  | m_exit_function (); | 
|  | } | 
|  |  | 
|  | /* The function to call on scope exit.  */ | 
|  | EF m_exit_function; | 
|  | }; | 
|  |  | 
|  | template <typename EF> | 
|  | scope_exit<typename std::decay<EF>::type> | 
|  | make_scope_exit (EF &&f) | 
|  | { | 
|  | return scope_exit<typename std::decay<EF>::type> (std::forward<EF> (f)); | 
|  | } | 
|  |  | 
|  | namespace detail | 
|  | { | 
|  |  | 
|  | enum class scope_exit_lhs {}; | 
|  |  | 
|  | template<typename EF> | 
|  | scope_exit<typename std::decay<EF>::type> | 
|  | operator+ (scope_exit_lhs, EF &&rhs) | 
|  | { | 
|  | return scope_exit<typename std::decay<EF>::type> (std::forward<EF> (rhs)); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | /* Register a block of code to run on scope exit.  Note that the local | 
|  | context is captured by reference, which means you should be careful | 
|  | to avoid inadvertently changing a captured local's value before the | 
|  | scope exit runs.  */ | 
|  |  | 
|  | #define SCOPE_EXIT \ | 
|  | auto CONCAT(scope_exit_, __LINE__) = ::detail::scope_exit_lhs () + [&] () | 
|  |  | 
|  | #endif /* COMMON_SCOPE_EXIT_H */ |