1/*
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * https://www.boost.org/LICENSE_1_0.txt)
5 *
6 * Copyright (c) 2022 Andrey Semashev
7 */
8/*!
9 * \file scope/scope_success.hpp
10 *
11 * This header contains definition of \c scope_success template.
12 */
13
14#ifndef BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
15#define BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
16
17#include <type_traits>
18#include <boost/scope/detail/config.hpp>
19#include <boost/scope/exception_checker.hpp>
20#include <boost/scope/scope_exit.hpp>
21#include <boost/scope/detail/is_not_like.hpp>
22#include <boost/scope/detail/type_traits/conjunction.hpp>
23#include <boost/scope/detail/type_traits/is_invocable.hpp>
24#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
25#include <boost/scope/detail/header.hpp>
26
27#ifdef BOOST_HAS_PRAGMA_ONCE
28#pragma once
29#endif
30
31namespace boost {
32namespace scope {
33
34template< typename Func, typename Cond >
35class scope_success;
36
37namespace detail {
38
39// Workaround for clang < 5.0 which can't pass scope_success as a template template parameter from within scope_success definition
40template< typename T >
41using is_not_like_scope_success = detail::is_not_like< T, scope_success >;
42
43template< typename Func >
44class logical_not;
45
46template< typename T >
47using is_not_like_logical_not = detail::is_not_like< T, logical_not >;
48
49template< typename Func >
50class logical_not
51{
52public:
53 using result_type = bool;
54
55private:
56 Func m_func;
57
58public:
59 template<
60 bool Requires = std::is_default_constructible< Func >::value,
61 typename = typename std::enable_if< Requires >::type
62 >
63 logical_not() noexcept(std::is_nothrow_default_constructible< Func >::value) :
64 m_func()
65 {
66 }
67
68 template<
69 typename F,
70 typename = typename std::enable_if< detail::conjunction<
71 std::is_constructible< Func, F >,
72 detail::is_not_like_logical_not< F >
73 >::value >::type
74 >
75 explicit logical_not(F&& func) noexcept(std::is_nothrow_constructible< Func, F >::value) :
76 m_func(static_cast< F&& >(func))
77 {
78 }
79
80 result_type operator()() const noexcept(detail::is_nothrow_invocable< Func const& >::value)
81 {
82 return !m_func();
83 }
84};
85
86} // namespace detail
87
88/*!
89 * \brief Scope exit guard that invokes a function upon leaving the scope, if
90 * a failure condition is not satisfied.
91 *
92 * The scope guard wraps two function objects: the scope guard action and
93 * a failure condition for invoking the action. Both function objects must
94 * be callable with no arguments and can be one of:
95 *
96 * \li A user-defined class with a public `operator()`.
97 * \li An lvalue reference to such class.
98 * \li An lvalue reference or pointer to function taking no arguments.
99 *
100 * The condition function object `operator()` must return a value
101 * contextually convertible to \c true, if the failure is detected and the
102 * action function object is not allowed to be executed, and \c false otherwise.
103 * Additionally, the failure condition function object `operator()` must not
104 * throw, as otherwise the action function object may not be called. If not
105 * specified, the default failure condition checks whether the scope is left
106 * due to an exception - the action function object will only be called if
107 * the scope is left normally.
108 *
109 * \sa scope_exit
110 * \sa scope_fail
111 *
112 * \tparam Func Scope guard action function object type.
113 * \tparam Cond Scope guard failure condition function object type.
114 */
115template< typename Func, typename Cond = exception_checker >
116class scope_success :
117 public scope_exit< Func, detail::logical_not< Cond > >
118{
119//! \cond
120private:
121 using base_type = scope_exit< Func, detail::logical_not< Cond > >;
122
123//! \endcond
124public:
125 /*!
126 * \brief Constructs a scope guard with a given callable function object.
127 *
128 * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible.
129 *
130 * **Effects:** Constructs the scope guard as if by calling
131 * `scope_success(std::forward< F >(func), Cond(), active)`.
132 *
133 * **Throws:** Nothing, unless construction of the function objects throw.
134 *
135 * \param func The callable action function object to invoke on destruction.
136 * \param active Indicates whether the scope guard should be active upon construction.
137 *
138 * \post `this->active() == active`
139 */
140 template<
141 typename F
142 //! \cond
143 , typename = typename std::enable_if< detail::conjunction<
144 std::is_constructible< base_type, F, bool >,
145 detail::is_not_like_scope_success< F >
146 >::value >::type
147 //! \endcond
148 >
149 explicit scope_success(F&& func, bool active = true)
150 noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, bool >::value)) :
151 base_type(static_cast< F&& >(func), active)
152 {
153 }
154
155 /*!
156 * \brief Constructs a scope guard with a given callable action and failure condition function objects.
157 *
158 * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond.
159 *
160 * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
161 * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is
162 * nothrow constructible from `C&&` then constructs \c Cond from
163 * `std::forward< C >(cond)`, otherwise constructs from `cond`.
164 *
165 * If \c Func or \c Cond construction throws and \a active is \c true, invokes
166 * \a cond and, if it returns \c true, \a func before returning with the exception.
167 *
168 * **Throws:** Nothing, unless construction of the function objects throw.
169 *
170 * \param func The callable action function object to invoke on destruction.
171 * \param cond The callable failure condition function object.
172 * \param active Indicates whether the scope guard should be active upon construction.
173 *
174 * \post `this->active() == active`
175 */
176 template<
177 typename F,
178 typename C
179 //! \cond
180 , typename = typename std::enable_if< std::is_constructible< base_type, F, C, bool >::value >::type
181 //! \endcond
182 >
183 explicit scope_success(F&& func, C&& cond, bool active = true)
184 noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, C, bool >::value)) :
185 base_type(static_cast< F&& >(func), static_cast< C&& >(cond), active)
186 {
187 }
188
189 /*!
190 * \brief Move-constructs a scope guard.
191 *
192 * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible.
193 *
194 * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from
195 * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow
196 * move-constructible then move-constructs \c Cond from a member of \a that,
197 * otherwise copy-constructs \c Cond.
198 *
199 * If \c Func or \c Cond construction throws and `that.active() == true`, invokes
200 * \c Cond object stored in \a that and, if it returns \c true, \a Func object
201 * (either the newly constructed one, if its construction succeeded, or the original
202 * one stored in \a that) before returning with the exception.
203 *
204 * If the construction succeeds, marks \a that as inactive.
205 *
206 * **Throws:** Nothing, unless move-construction of the function objects throw.
207 *
208 * \param that Move source.
209 *
210 * \post `that.active() == false`
211 */
212 //! \cond
213 template<
214 bool Requires = std::is_move_constructible< base_type >::value,
215 typename = typename std::enable_if< Requires >::type
216 >
217 //! \endcond
218 scope_success(scope_success&& that)
219 noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< base_type >::value)) :
220 base_type(static_cast< base_type&& >(that))
221 {
222 }
223
224 scope_success& operator= (scope_success&&) = delete;
225
226 scope_success(scope_success const&) = delete;
227 scope_success& operator= (scope_success const&) = delete;
228};
229
230#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
231template< typename Func >
232explicit scope_success(Func) -> scope_success< Func >;
233
234template< typename Func >
235explicit scope_success(Func, bool) -> scope_success< Func >;
236
237template<
238 typename Func,
239 typename Cond,
240 typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
241>
242explicit scope_success(Func, Cond) -> scope_success< Func, Cond >;
243
244template<
245 typename Func,
246 typename Cond,
247 typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
248>
249explicit scope_success(Func, Cond, bool) -> scope_success< Func, Cond >;
250#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
251
252/*!
253 * \brief Creates a scope fail guard with a given action function object.
254 *
255 * **Effects:** Constructs a scope guard as if by calling
256 * `scope_success< std::decay_t< F > >(std::forward< F >(func), active)`.
257 *
258 * \param func The callable function object to invoke on destruction.
259 * \param active Indicates whether the scope guard should be active upon construction.
260 */
261template< typename F >
262inline scope_success< typename std::decay< F >::type > make_scope_success(F&& func, bool active = true)
263 noexcept(std::is_nothrow_constructible<
264 scope_success< typename std::decay< F >::type >,
265 F,
266 bool
267 >::value)
268{
269 return scope_success< typename std::decay< F >::type >(static_cast< F&& >(func), active);
270}
271
272/*!
273 * \brief Creates a scope fail with given callable function objects.
274 *
275 * **Effects:** Constructs a scope guard as if by calling
276 * `scope_success< std::decay_t< F >, std::decay_t< C > >(
277 * std::forward< F >(func), std::forward< C >(cond), active)`.
278 *
279 * \param func The callable action function object to invoke on destruction.
280 * \param cond The callable failure condition function object.
281 * \param active Indicates whether the scope guard should be active upon construction.
282 */
283template< typename F, typename C >
284inline
285#if !defined(BOOST_SCOPE_DOXYGEN)
286typename std::enable_if<
287 detail::is_invocable< C const& >::value,
288 scope_success< typename std::decay< F >::type, typename std::decay< C >::type >
289>::type
290#else
291scope_success< typename std::decay< F >::type, typename std::decay< C >::type >
292#endif
293make_scope_success(F&& func, C&& cond, bool active = true)
294 noexcept(std::is_nothrow_constructible<
295 scope_success< typename std::decay< F >::type, typename std::decay< C >::type >,
296 F,
297 C,
298 bool
299 >::value)
300{
301 return scope_success< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active);
302}
303
304} // namespace scope
305} // namespace boost
306
307#include <boost/scope/detail/footer.hpp>
308
309#endif // BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
310

source code of boost/libs/scope/include/boost/scope/scope_success.hpp