scope_fail.hpp 9.6 KB

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