1 /* Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 This file is part of GDB.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 #ifndef COMMON_SCOPE_EXIT_H
19 #define COMMON_SCOPE_EXIT_H
22 #include <type_traits>
23 #include "gdbsupport/preprocessor.h"
25 /* scope_exit is a general-purpose scope guard that calls its exit
26 function at the end of the current scope. A scope_exit may be
27 canceled by calling the "release" method. The API is modeled on
28 P0052R5 - Generic Scope Guard and RAII Wrapper for the Standard
29 Library, which is itself based on Andrej Alexandrescu's
30 ScopeGuard/SCOPE_EXIT.
32 There are two forms available:
34 - The "make_scope_exit" form allows canceling the scope guard. Use
37 auto cleanup = make_scope_exit ( <function, function object, lambda> );
39 cleanup.release (); // cancel
41 - If you don't need to cancel the guard, you can use the SCOPE_EXIT
46 // any code you like here.
49 See also forward_scope_exit.
52 /* CRTP base class for cancelable scope_exit-like classes. Implements
53 the common call-custom-function-from-dtor functionality. Classes
54 that inherit this implement the on_exit() method, which is called
55 from scope_exit_base's dtor. */
57 template <typename CRTP
>
61 scope_exit_base () = default;
67 auto *self
= static_cast<CRTP
*> (this);
72 /* This is needed for make_scope_exit because copy elision isn't
73 guaranteed until C++17. An optimizing compiler will usually skip
74 calling this, but it must exist. */
75 scope_exit_base (const scope_exit_base
&other
)
76 : m_released (other
.m_released
)
78 other
.m_released
= true;
81 void operator= (const scope_exit_base
&) = delete;
83 /* If this is called, then the wrapped function will not be called
85 void release () noexcept
92 /* True if released. Mutable because of the copy ctor hack
94 mutable bool m_released
= false;
97 /* The scope_exit class. */
100 class scope_exit
: public scope_exit_base
<scope_exit
<EF
>>
102 /* For access to on_exit(). */
103 friend scope_exit_base
<scope_exit
<EF
>>;
107 template<typename EFP
,
108 typename
= gdb::Requires
<std::is_constructible
<EF
, EFP
>>>
110 try : m_exit_function ((!std::is_lvalue_reference
<EFP
>::value
111 && std::is_nothrow_constructible
<EF
, EFP
>::value
)
118 /* "If the initialization of exit_function throws an exception,
123 template<typename EFP
,
124 typename
= gdb::Requires
<std::is_constructible
<EF
, EFP
>>>
125 scope_exit (scope_exit
&&rhs
)
126 noexcept (std::is_nothrow_move_constructible
<EF
>::value
127 || std::is_nothrow_copy_constructible
<EF
>::value
)
128 : m_exit_function (std::is_nothrow_constructible
<EFP
>::value
135 /* This is needed for make_scope_exit because copy elision isn't
136 guaranteed until C++17. An optimizing compiler will usually skip
137 calling this, but it must exist. */
138 scope_exit (const scope_exit
&other
)
139 : scope_exit_base
<scope_exit
<EF
>> (other
),
140 m_exit_function (other
.m_exit_function
)
144 void operator= (const scope_exit
&) = delete;
145 void operator= (scope_exit
&&) = delete;
153 /* The function to call on scope exit. */
157 template <typename EF
>
158 scope_exit
<typename
std::decay
<EF
>::type
>
159 make_scope_exit (EF
&&f
)
161 return scope_exit
<typename
std::decay
<EF
>::type
> (std::forward
<EF
> (f
));
167 enum class scope_exit_lhs
{};
169 template<typename EF
>
170 scope_exit
<typename
std::decay
<EF
>::type
>
171 operator+ (scope_exit_lhs
, EF
&&rhs
)
173 return scope_exit
<typename
std::decay
<EF
>::type
> (std::forward
<EF
> (rhs
));
178 /* Register a block of code to run on scope exit. Note that the local
179 context is captured by reference, which means you should be careful
180 to avoid inadvertently changing a captured local's value before the
184 auto CONCAT(scope_exit_, __LINE__) = ::detail::scope_exit_lhs () + [&] ()
186 #endif /* COMMON_SCOPE_EXIT_H */