Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:44:21

0001 /*
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * https://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * Copyright (c) 2023 Andrey Semashev
0007  */
0008 /*!
0009  * \file scope/scope_exit.hpp
0010  *
0011  * This header contains definition of \c scope_exit template.
0012  */
0013 
0014 #ifndef BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_
0015 #define BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_
0016 
0017 #include <type_traits>
0018 #include <boost/scope/detail/config.hpp>
0019 #include <boost/scope/detail/is_not_like.hpp>
0020 #include <boost/scope/detail/compact_storage.hpp>
0021 #include <boost/scope/detail/move_or_copy_construct_ref.hpp>
0022 #include <boost/scope/detail/is_nonnull_default_constructible.hpp>
0023 #include <boost/scope/detail/type_traits/conjunction.hpp>
0024 #include <boost/scope/detail/type_traits/is_invocable.hpp>
0025 #include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
0026 #include <boost/scope/detail/header.hpp>
0027 
0028 #ifdef BOOST_HAS_PRAGMA_ONCE
0029 #pragma once
0030 #endif
0031 
0032 namespace boost {
0033 namespace scope {
0034 
0035 template< typename Func, typename Cond >
0036 class scope_exit;
0037 
0038 namespace detail {
0039 
0040 // Workaround for clang < 5.0 which can't pass scope_exit as a template template parameter from within scope_exit definition
0041 template< typename T >
0042 using is_not_like_scope_exit = detail::is_not_like< T, scope_exit >;
0043 
0044 //! The scope guard used to invoke the condition and action functions in case of exception during scope guard construction
0045 template< typename Func, typename Cond >
0046 class init_guard
0047 {
0048 private:
0049     Func& m_func;
0050     Cond& m_cond;
0051     bool m_active;
0052 
0053 public:
0054     init_guard(Func& func, Cond& cond, bool active) noexcept :
0055         m_func(func),
0056         m_cond(cond),
0057         m_active(active)
0058     {
0059     }
0060 
0061     init_guard(init_guard const&) = delete;
0062     init_guard& operator= (init_guard const&) = delete;
0063 
0064     ~init_guard()
0065         noexcept(detail::conjunction<
0066             detail::is_nothrow_invocable< Func& >,
0067             detail::is_nothrow_invocable< Cond& >
0068         >::value)
0069     {
0070         if (m_active && m_cond())
0071             m_func();
0072     }
0073 
0074     Func&& get_func() noexcept
0075     {
0076         return static_cast< Func&& >(m_func);
0077     }
0078 
0079     Cond&& get_cond() noexcept
0080     {
0081         return static_cast< Cond&& >(m_cond);
0082     }
0083 
0084     void deactivate() noexcept
0085     {
0086         m_active = false;
0087     }
0088 };
0089 
0090 } // namespace detail
0091 
0092 /*!
0093  * \brief A predicate that always returns \c true.
0094  *
0095  * This predicate can be used as the default condition function object for
0096  * \c scope_exit and similar scope guards.
0097  */
0098 class always_true
0099 {
0100 public:
0101     //! Predicate result type
0102     using result_type = bool;
0103 
0104     /*!
0105      * **Throws:** Nothing.
0106      *
0107      * \returns \c true.
0108      */
0109     result_type operator()() const noexcept
0110     {
0111         return true;
0112     }
0113 };
0114 
0115 /*!
0116  * \brief Scope exit guard that conditionally invokes a function upon leaving the scope.
0117  *
0118  * The scope guard wraps two function objects: the scope guard action and
0119  * a condition for invoking the action. Both function objects must be
0120  * callable with no arguments and can be one of:
0121  *
0122  * \li A user-defined class with a public `operator()`.
0123  * \li An lvalue reference to such class.
0124  * \li An lvalue reference or pointer to function taking no arguments.
0125  *
0126  * The condition function object `operator()` must return a value
0127  * contextually convertible to \c true, if the action function object
0128  * is allowed to be executed, and \c false otherwise. Additionally,
0129  * the condition function object `operator()` must not throw, as
0130  * otherwise the action function object may not be called.
0131  *
0132  * The condition function object is optional, and if not specified in
0133  * template parameters, the scope guard will operate as if the condition
0134  * always returns \c true.
0135  *
0136  * The scope guard can be in either active or inactive state. By default,
0137  * the constructed scope guard is active. When active, and condition
0138  * function object returns \c true, the scope guard invokes the wrapped
0139  * action function object on destruction. Otherwise, the scope guard
0140  * does not call the wrapped action function object.
0141  *
0142  * The scope guard can be made inactive by moving-from the scope guard
0143  * or calling `set_active(false)`. An inactive scope guard can be made
0144  * active by calling `set_active(true)`. If a moved-from scope guard
0145  * is active on destruction, the behavior is undefined.
0146  *
0147  * \tparam Func Scope guard action function object type.
0148  * \tparam Cond Scope guard condition function object type.
0149  */
0150 template< typename Func, typename Cond = always_true >
0151 class scope_exit
0152 {
0153 //! \cond
0154 private:
0155     struct func_holder :
0156         public detail::compact_storage< Func >
0157     {
0158         using func_base = detail::compact_storage< Func >;
0159 
0160         template<
0161             typename F,
0162             typename C,
0163             typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type
0164         >
0165         explicit func_holder(F&& func, C&& cond, bool active, std::true_type) noexcept :
0166             func_base(static_cast< F&& >(func))
0167         {
0168         }
0169 
0170         template<
0171             typename F,
0172             typename C,
0173             typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type
0174         >
0175         explicit func_holder(F&& func, C&& cond, bool active, std::false_type) :
0176             func_holder(detail::init_guard< F, C >(func, cond, active))
0177         {
0178         }
0179 
0180     private:
0181         template< typename F, typename C >
0182         explicit func_holder(detail::init_guard< F, C >&& init) :
0183             func_base(init.get_func())
0184         {
0185             init.deactivate();
0186         }
0187     };
0188 
0189     struct cond_holder :
0190         public detail::compact_storage< Cond >
0191     {
0192         using cond_base = detail::compact_storage< Cond >;
0193 
0194         template<
0195             typename C,
0196             typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type
0197         >
0198         explicit cond_holder(C&& cond, Func& func, bool active, std::true_type) noexcept :
0199             cond_base(static_cast< C&& >(cond))
0200         {
0201         }
0202 
0203         template<
0204             typename C,
0205             typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type
0206         >
0207         explicit cond_holder(C&& cond, Func& func, bool active, std::false_type) :
0208             cond_holder(detail::init_guard< Func&, C >(func, cond, active))
0209         {
0210         }
0211 
0212     private:
0213         template< typename C >
0214         explicit cond_holder(detail::init_guard< Func&, C >&& init) :
0215             cond_base(init.get_cond())
0216         {
0217             init.deactivate();
0218         }
0219     };
0220 
0221     struct data :
0222         public func_holder,
0223         public cond_holder
0224     {
0225         bool m_active;
0226 
0227         template<
0228             typename F,
0229             typename C,
0230             typename = typename std::enable_if< detail::conjunction<
0231                 std::is_constructible< func_holder, F, C, bool, typename std::is_nothrow_constructible< Func, F >::type >,
0232                 std::is_constructible< cond_holder, C, Func&, bool, typename std::is_nothrow_constructible< Cond, C >::type >
0233             >::value >::type
0234         >
0235         explicit data(F&& func, C&& cond, bool active)
0236             noexcept(detail::conjunction< std::is_nothrow_constructible< Func, F >, std::is_nothrow_constructible< Cond, C > >::value) :
0237             func_holder(static_cast< F&& >(func), static_cast< C&& >(cond), active, typename std::is_nothrow_constructible< Func, F >::type()),
0238             cond_holder(static_cast< C&& >(cond), func_holder::get(), active, typename std::is_nothrow_constructible< Cond, C >::type()),
0239             m_active(active)
0240         {
0241         }
0242 
0243         Func& get_func() noexcept
0244         {
0245             return func_holder::get();
0246         }
0247 
0248         Func const& get_func() const noexcept
0249         {
0250             return func_holder::get();
0251         }
0252 
0253         Cond& get_cond() noexcept
0254         {
0255             return cond_holder::get();
0256         }
0257 
0258         Cond const& get_cond() const noexcept
0259         {
0260             return cond_holder::get();
0261         }
0262 
0263         bool deactivate() noexcept
0264         {
0265             bool active = m_active;
0266             m_active = false;
0267             return active;
0268         }
0269     };
0270 
0271     data m_data;
0272 
0273 //! \endcond
0274 public:
0275     /*!
0276      * \brief Constructs a scope guard with a given callable action function object.
0277      *
0278      * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible
0279      *               and is not a pointer to function.
0280      *
0281      * \note The requirement for \c Cond default constructor to be non-throwing is to allow for
0282      *       the condition function object to be called in case if constructing either function
0283      *       object throws.
0284      *
0285      * **Effects:** Constructs the scope guard as if by calling
0286      *              `scope_exit(std::forward< F >(func), Cond(), active)`.
0287      *
0288      * **Throws:** Nothing, unless construction of the function objects throw.
0289      *
0290      * \param func The callable action function object to invoke on destruction.
0291      * \param active Indicates whether the scope guard should be active upon construction.
0292      *
0293      * \post `this->active() == active`
0294      */
0295     template<
0296         typename F
0297         //! \cond
0298         , typename = typename std::enable_if< detail::conjunction<
0299             detail::is_nothrow_nonnull_default_constructible< Cond >,
0300             std::is_constructible<
0301                 data,
0302                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0303                 typename detail::move_or_copy_construct_ref< Cond >::type,
0304                 bool
0305             >,
0306             detail::is_not_like_scope_exit< F >
0307         >::value >::type
0308         //! \endcond
0309     >
0310     explicit scope_exit(F&& func, bool active = true)
0311         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
0312             std::is_nothrow_constructible<
0313                 data,
0314                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0315                 typename detail::move_or_copy_construct_ref< Cond >::type,
0316                 bool
0317             >::value
0318         )) :
0319         m_data
0320         (
0321             static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
0322             static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(Cond()),
0323             active
0324         )
0325     {
0326     }
0327 
0328     /*!
0329      * \brief Constructs a scope guard with a given callable action and condition function objects.
0330      *
0331      * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond.
0332      *
0333      * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
0334      *              `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is
0335      *              nothrow constructible from `C&&` then constructs \c Cond from
0336      *              `std::forward< C >(cond)`, otherwise constructs from `cond`.
0337      *
0338      *              If \c Func or \c Cond construction throws and \a active is \c true, invokes
0339      *              \a cond and, if it returns \c true, \a func before returning with the exception.
0340      *
0341      * **Throws:** Nothing, unless construction of the function objects throw.
0342      *
0343      * \param func The callable action function object to invoke on destruction.
0344      * \param cond The callable condition function object.
0345      * \param active Indicates whether the scope guard should be active upon construction.
0346      *
0347      * \post `this->active() == active`
0348      */
0349     template<
0350         typename F,
0351         typename C
0352         //! \cond
0353         , typename = typename std::enable_if< detail::conjunction<
0354             detail::is_invocable< C const& >,
0355             std::is_constructible<
0356                 data,
0357                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0358                 typename detail::move_or_copy_construct_ref< C, Cond >::type,
0359                 bool
0360             >
0361         >::value >::type
0362         //! \endcond
0363     >
0364     explicit scope_exit(F&& func, C&& cond, bool active = true)
0365         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
0366             std::is_nothrow_constructible<
0367                 data,
0368                 typename detail::move_or_copy_construct_ref< F, Func >::type,
0369                 typename detail::move_or_copy_construct_ref< C, Cond >::type,
0370                 bool
0371             >::value
0372         )) :
0373         m_data
0374         (
0375             static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
0376             static_cast< typename detail::move_or_copy_construct_ref< C, Cond >::type >(cond),
0377             active
0378         )
0379     {
0380     }
0381 
0382     /*!
0383      * \brief Move-constructs a scope guard.
0384      *
0385      * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible.
0386      *
0387      * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from
0388      *              a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow
0389      *              move-constructible then move-constructs \c Cond from a member of \a that,
0390      *              otherwise copy-constructs \c Cond.
0391      *
0392      *              If \c Func or \c Cond construction throws and `that.active() == true`, invokes
0393      *              \c Cond object stored in \a that and, if it returns \c true, \a Func object
0394      *              (either the newly constructed one, if its construction succeeded, or the original
0395      *              one stored in \a that) before returning with the exception.
0396      *
0397      *              If the construction succeeds, marks \a that as inactive.
0398      *
0399      * **Throws:** Nothing, unless move-construction of the function objects throw.
0400      *
0401      * \param that Move source.
0402      *
0403      * \post `that.active() == false`
0404      */
0405     //! \cond
0406     template<
0407         bool Requires = std::is_constructible<
0408             data,
0409             typename detail::move_or_copy_construct_ref< Func >::type,
0410             typename detail::move_or_copy_construct_ref< Cond >::type,
0411             bool
0412         >::value,
0413         typename = typename std::enable_if< Requires >::type
0414     >
0415     //! \endcond
0416     scope_exit(scope_exit&& that)
0417         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
0418             std::is_nothrow_constructible<
0419                 data,
0420                 typename detail::move_or_copy_construct_ref< Func >::type,
0421                 typename detail::move_or_copy_construct_ref< Cond >::type,
0422                 bool
0423             >::value
0424         )) :
0425         m_data
0426         (
0427             static_cast< typename detail::move_or_copy_construct_ref< Func >::type >(that.m_data.get_func()),
0428             static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(that.m_data.get_cond()),
0429             that.m_data.deactivate()
0430         )
0431     {
0432     }
0433 
0434     scope_exit& operator= (scope_exit&&) = delete;
0435 
0436     scope_exit(scope_exit const&) = delete;
0437     scope_exit& operator= (scope_exit const&) = delete;
0438 
0439     /*!
0440      * \brief If `active() == true`, and invoking the condition function object returns \c true, invokes
0441      *        the wrapped callable action function object. Destroys the function objects.
0442      *
0443      * **Throws:** Nothing, unless invoking a function object throws.
0444      */
0445     ~scope_exit()
0446         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
0447             detail::conjunction<
0448                 detail::is_nothrow_invocable< Func& >,
0449                 detail::is_nothrow_invocable< Cond& >
0450             >::value
0451         ))
0452     {
0453         if (BOOST_LIKELY(m_data.m_active && m_data.get_cond()()))
0454             m_data.get_func()();
0455     }
0456 
0457     /*!
0458      * \brief Returns \c true if the scope guard is active, otherwise \c false.
0459      *
0460      * \note This method does not call the condition function object specified on construction.
0461      *
0462      * **Throws:** Nothing.
0463      */
0464     bool active() const noexcept
0465     {
0466         return m_data.m_active;
0467     }
0468 
0469     /*!
0470      * \brief Activates or deactivates the scope guard.
0471      *
0472      * **Throws:** Nothing.
0473      *
0474      * \param active The active status to set.
0475      *
0476      * \post `this->active() == active`
0477      */
0478     void set_active(bool active) noexcept
0479     {
0480         m_data.m_active = active;
0481     }
0482 };
0483 
0484 #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
0485 template< typename Func >
0486 explicit scope_exit(Func) -> scope_exit< Func >;
0487 
0488 template< typename Func >
0489 explicit scope_exit(Func, bool) -> scope_exit< Func >;
0490 
0491 template< typename Func, typename Cond >
0492 explicit scope_exit(Func, Cond) -> scope_exit< Func, Cond >;
0493 
0494 template< typename Func, typename Cond >
0495 explicit scope_exit(Func, Cond, bool) -> scope_exit< Func, Cond >;
0496 #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
0497 
0498 /*!
0499  * \brief Creates a scope guard with a given action function object.
0500  *
0501  * **Effects:** Constructs a scope guard as if by calling
0502  *              `scope_exit< std::decay_t< F > >(std::forward< F >(func), active)`.
0503  *
0504  * \param func The callable action function object to invoke on destruction.
0505  * \param active Indicates whether the scope guard should be active upon construction.
0506  */
0507 template< typename F >
0508 inline scope_exit< typename std::decay< F >::type > make_scope_exit(F&& func, bool active = true)
0509     noexcept(std::is_nothrow_constructible<
0510         scope_exit< typename std::decay< F >::type >,
0511         F,
0512         bool
0513     >::value)
0514 {
0515     return scope_exit< typename std::decay< F >::type >(static_cast< F&& >(func), active);
0516 }
0517 
0518 /*!
0519  * \brief Creates a conditional scope guard with given callable function objects.
0520  *
0521  * **Effects:** Constructs a scope guard as if by calling
0522  *              `scope_exit< std::decay_t< F >, std::decay_t< C > >(
0523  *              std::forward< F >(func), std::forward< C >(cond), active)`.
0524  *
0525  * \param func The callable action function object to invoke on destruction.
0526  * \param cond The callable condition function object.
0527  * \param active Indicates whether the scope guard should be active upon construction.
0528  */
0529 template< typename F, typename C >
0530 inline
0531 #if !defined(BOOST_SCOPE_DOXYGEN)
0532 typename std::enable_if<
0533     std::is_constructible<
0534         scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >,
0535         F,
0536         C,
0537         bool
0538     >::value,
0539     scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >
0540 >::type
0541 #else
0542 scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >
0543 #endif
0544 make_scope_exit(F&& func, C&& cond, bool active = true)
0545     noexcept(std::is_nothrow_constructible<
0546         scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >,
0547         F,
0548         C,
0549         bool
0550     >::value)
0551 {
0552     return scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active);
0553 }
0554 
0555 } // namespace scope
0556 } // namespace boost
0557 
0558 #include <boost/scope/detail/footer.hpp>
0559 
0560 #endif // BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_