| #pragma once | #pragma once | ||||
| #include <utility> | |||||
| #include <type_traits> | |||||
| #include "scope_guard_base.h" | |||||
| #include <exception> | #include <exception> | ||||
| namespace sr | namespace sr | ||||
| { | { | ||||
| template<class EF> | |||||
| class scope_fail | |||||
| namespace detail | |||||
| { | { | ||||
| public: | |||||
| template<class EFP, | |||||
| std::enable_if_t<std::is_constructible<EF, EFP>::value, int> = 0, | |||||
| std::enable_if_t<(!std::is_lvalue_reference<EFP>::value) | |||||
| && std::is_nothrow_constructible<EF, EFP>::value, int> = 0 | |||||
| > | |||||
| explicit scope_fail(EFP&& exitFunction) : m_exitFunction(std::move(exitFunction)), | |||||
| m_execute_on_destruction(true), | |||||
| m_uncaught_on_creation(uncaught_exceptions()) | |||||
| { | |||||
| } | |||||
| template<class EFP, | |||||
| std::enable_if_t<std::is_constructible<EF, EFP>::value, int> = 0, | |||||
| std::enable_if_t<std::is_lvalue_reference<EFP>::value, int> = 0 | |||||
| > | |||||
| explicit scope_fail(EFP&& exitFunction) try : m_exitFunction(exitFunction), | |||||
| m_execute_on_destruction(true), | |||||
| m_uncaught_on_creation(uncaught_exceptions()) | |||||
| struct scope_fail_strategy | |||||
| { | { | ||||
| } | |||||
| catch( ... ) | |||||
| { | |||||
| exitFunction(); | |||||
| throw; | |||||
| } | |||||
| scope_fail(const scope_fail&) = delete; | |||||
| template<class T = EF, | |||||
| std::enable_if_t<std::is_nothrow_move_constructible<T>::value, int> = 0 | |||||
| > | |||||
| scope_fail(scope_fail&& other) noexcept(std::is_nothrow_move_constructible<T>::value || std::is_nothrow_copy_constructible<T>::value) | |||||
| : m_exitFunction(std::move(other.m_exitFunction)), | |||||
| m_execute_on_destruction(other.m_execute_on_destruction), | |||||
| m_uncaught_on_creation(uncaught_exceptions()) | |||||
| { | |||||
| other.release(); | |||||
| } | |||||
| template<class T = EF, | |||||
| std::enable_if_t<!std::is_nothrow_move_constructible<T>::value, int> = 0 | |||||
| > | |||||
| scope_fail(scope_fail&& other) noexcept(std::is_nothrow_move_constructible<T>::value || std::is_nothrow_copy_constructible<T>::value) | |||||
| : m_exitFunction(other.m_exitFunction), | |||||
| m_execute_on_destruction(other.m_execute_on_destruction), | |||||
| m_uncaught_on_creation(other.m_uncaught_on_creation) | |||||
| { | |||||
| other.release(); | |||||
| } | |||||
| bool should_execute() const | |||||
| { | |||||
| return uncaught_exceptions() > m_uncaught_on_creation; | |||||
| } | |||||
| ~scope_fail() noexcept(true) | |||||
| { | |||||
| if( ( m_execute_on_destruction == true ) && ( uncaught_exceptions() > m_uncaught_on_creation ) ) | |||||
| int uncaught_exceptions() const noexcept | |||||
| { | { | ||||
| m_exitFunction(); | |||||
| return ( std::uncaught_exception() == true ? 1 : 0 ); | |||||
| } | } | ||||
| } | |||||
| void release() noexcept | |||||
| { | |||||
| m_execute_on_destruction = false; | |||||
| } | |||||
| int m_uncaught_on_creation = uncaught_exceptions(); | |||||
| }; | |||||
| } | |||||
| scope_fail& operator=(const scope_fail&) = delete; | |||||
| scope_fail& operator=(scope_fail&&) = delete; | |||||
| template<class EF> | |||||
| class scope_fail : public detail::scope_guard_base<EF, detail::scope_fail_strategy> | |||||
| { | |||||
| public: | |||||
| using detail::scope_guard_base<EF, detail::scope_fail_strategy>::scope_guard_base; | |||||
| private: | |||||
| int uncaught_exceptions() const noexcept | |||||
| { | |||||
| return ( std::uncaught_exception() == true ? 1 : 0 ); | |||||
| } | |||||
| private: | |||||
| EF m_exitFunction; | |||||
| bool m_execute_on_destruction; | |||||
| int m_uncaught_on_creation; | |||||
| }; | }; | ||||