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

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