scope_success.hpp 11 KB

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