Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:52

0001 ///////////////////////////////////////////////////////////////////////////////
0002 // Copyright (c) Lewis Baker
0003 // Licenced under MIT license. See LICENSE.txt for details.
0004 ///////////////////////////////////////////////////////////////////////////////
0005 #ifndef CPPCORO_ON_SCOPE_EXIT_HPP_INCLUDED
0006 #define CPPCORO_ON_SCOPE_EXIT_HPP_INCLUDED
0007 
0008 #include <type_traits>
0009 #include <exception>
0010 
0011 namespace cppcoro
0012 {
0013     template<typename FUNC>
0014     class scoped_lambda
0015     {
0016     public:
0017 
0018         scoped_lambda(FUNC&& func)
0019             : m_func(std::forward<FUNC>(func))
0020             , m_cancelled(false)
0021         {}
0022 
0023         scoped_lambda(const scoped_lambda& other) = delete;
0024 
0025         scoped_lambda(scoped_lambda&& other)
0026             : m_func(std::forward<FUNC>(other.m_func))
0027             , m_cancelled(other.m_cancelled)
0028         {
0029             other.cancel();
0030         }
0031 
0032         ~scoped_lambda()
0033         {
0034             if (!m_cancelled)
0035             {
0036                 m_func();
0037             }
0038         }
0039 
0040         void cancel()
0041         {
0042             m_cancelled = true;
0043         }
0044 
0045         void call_now()
0046         {
0047             m_cancelled = true;
0048             m_func();
0049         }
0050 
0051     private:
0052 
0053         FUNC m_func;
0054         bool m_cancelled;
0055 
0056     };
0057 
0058     /// A scoped lambda that executes the lambda when the object destructs
0059     /// but only if exiting due to an exception (CALL_ON_FAILURE = true) or
0060     /// only if not exiting due to an exception (CALL_ON_FAILURE = false).
0061     template<typename FUNC, bool CALL_ON_FAILURE>
0062     class conditional_scoped_lambda
0063     {
0064     public:
0065 
0066         conditional_scoped_lambda(FUNC&& func)
0067             : m_func(std::forward<FUNC>(func))
0068             , m_uncaughtExceptionCount(std::uncaught_exceptions())
0069             , m_cancelled(false)
0070         {}
0071 
0072         conditional_scoped_lambda(const conditional_scoped_lambda& other) = delete;
0073 
0074         conditional_scoped_lambda(conditional_scoped_lambda&& other)
0075             noexcept(std::is_nothrow_move_constructible<FUNC>::value)
0076             : m_func(std::forward<FUNC>(other.m_func))
0077             , m_uncaughtExceptionCount(other.m_uncaughtExceptionCount)
0078             , m_cancelled(other.m_cancelled)
0079         {
0080             other.cancel();
0081         }
0082 
0083         ~conditional_scoped_lambda() noexcept(CALL_ON_FAILURE || noexcept(std::declval<FUNC>()()))
0084         {
0085             if (!m_cancelled && (is_unwinding_due_to_exception() == CALL_ON_FAILURE))
0086             {
0087                 m_func();
0088             }
0089         }
0090 
0091         void cancel() noexcept
0092         {
0093             m_cancelled = true;
0094         }
0095 
0096     private:
0097 
0098         bool is_unwinding_due_to_exception() const noexcept
0099         {
0100             return std::uncaught_exceptions() > m_uncaughtExceptionCount;
0101         }
0102 
0103         FUNC m_func;
0104         int m_uncaughtExceptionCount;
0105         bool m_cancelled;
0106 
0107     };
0108 
0109     /// Returns an object that calls the provided function when it goes out
0110     /// of scope either normally or due to an uncaught exception unwinding
0111     /// the stack.
0112     ///
0113     /// \param func
0114     /// The function to call when the scope exits.
0115     /// The function must be noexcept.
0116     template<typename FUNC>
0117     auto on_scope_exit(FUNC&& func)
0118     {
0119         return scoped_lambda<FUNC>{ std::forward<FUNC>(func) };
0120     }
0121 
0122     /// Returns an object that calls the provided function when it goes out
0123     /// of scope due to an uncaught exception unwinding the stack.
0124     ///
0125     /// \param func
0126     /// The function to be called if unwinding due to an exception.
0127     /// The function must be noexcept.
0128     template<typename FUNC>
0129     auto on_scope_failure(FUNC&& func)
0130     {
0131         return conditional_scoped_lambda<FUNC, true>{ std::forward<FUNC>(func) };
0132     }
0133 
0134     /// Returns an object that calls the provided function when it goes out
0135     /// of scope via normal execution (ie. not unwinding due to an exception).
0136     ///
0137     /// \param func
0138     /// The function to call if the scope exits normally.
0139     /// The function does not necessarily need to be noexcept.
0140     template<typename FUNC>
0141     auto on_scope_success(FUNC&& func)
0142     {
0143         return conditional_scoped_lambda<FUNC, false>{ std::forward<FUNC>(func) };
0144     }
0145 }
0146 
0147 #endif