Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: Test

on:
workflow_dispatch:
pull_request:
push:
branches: [ "main" ]
Expand Down
57 changes: 42 additions & 15 deletions scope_guard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#ifndef SCOPE_GUARD_HPP_
#define SCOPE_GUARD_HPP_

#include <exception>
#include <type_traits>
#include <utility>

Expand All @@ -22,6 +23,13 @@

namespace sg
{
enum class ExitType {
ALWAYS,
#if __cplusplus >= 201411L
ON_SUCCESS,
ON_FAILURE,
#endif
};
namespace detail
{
/* --- Some custom type traits --- */
Expand Down Expand Up @@ -76,10 +84,29 @@ namespace sg
std::is_nothrow_destructible<T>>
{};

template<ExitType exit_type> struct ShouldRun;
template<> struct ShouldRun<ExitType::ALWAYS> {
constexpr static bool should_run() { return true; }
};
#if __cplusplus >= 201703L
template<> struct ShouldRun<ExitType::ON_SUCCESS> {
static bool should_run() { return std::uncaught_exceptions() == 0; }
};
template<> struct ShouldRun<ExitType::ON_FAILURE> {
static bool should_run() { return std::uncaught_exceptions() != 0; }
};
#elif __cplusplus >= 201411L
template<> struct ShouldRun<ExitType::ON_SUCCESS> {
static bool should_run() { return !std::uncaught_exception(); }
};
template<> struct ShouldRun<ExitType::ON_FAILURE> {
static bool should_run() { return std::uncaught_exception(); }
};
#endif

/* --- The actual scope_guard template --- */

template<typename Callback,
template<typename Callback, ExitType exit_type = ExitType::ALWAYS,
typename = typename std::enable_if<
is_proper_sg_callback_t<Callback>::value>::type>
class scope_guard;
Expand All @@ -97,8 +124,8 @@ namespace sg

/* --- The template specialization that actually defines the class --- */

template<typename Callback>
class SG_NODISCARD scope_guard<Callback> final
template<typename Callback, ExitType exit_type>
class SG_NODISCARD scope_guard<Callback, exit_type> final
{
public:
typedef Callback callback_type;
Expand Down Expand Up @@ -142,8 +169,8 @@ namespace sg
} // namespace sg

////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::scope_guard(Callback&& callback)
template<typename Callback, sg::ExitType exit_type>
sg::detail::scope_guard<Callback, exit_type>::scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
: m_callback(std::forward<Callback>(callback)) /* use () instead of {} because
of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers
Expand All @@ -153,17 +180,17 @@ noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
{}

////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::scope_guard::~scope_guard() noexcept /*
template<typename Callback, sg::ExitType exit_type>
sg::detail::scope_guard<Callback, exit_type>::scope_guard::~scope_guard() noexcept /*
need the extra injected-class-name here to make different compilers happy */
{
if(m_active)
if(m_active && ShouldRun<exit_type>::should_run())
m_callback();
}

////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
sg::detail::scope_guard<Callback>::scope_guard(scope_guard&& other)
template<typename Callback, sg::ExitType exit_type>
sg::detail::scope_guard<Callback, exit_type>::scope_guard(scope_guard&& other)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
: m_callback(std::forward<Callback>(other.m_callback)) // idem
, m_active{std::move(other.m_active)}
Expand All @@ -172,19 +199,19 @@ noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
}

////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
inline void sg::detail::scope_guard<Callback>::dismiss() noexcept
template<typename Callback, sg::ExitType exit_type>
inline void sg::detail::scope_guard<Callback, exit_type>::dismiss() noexcept
{
m_active = false;
}

////////////////////////////////////////////////////////////////////////////////
template<typename Callback>
template<typename Callback, sg::ExitType exit_type>
inline auto sg::detail::make_scope_guard(Callback&& callback)
noexcept(std::is_nothrow_constructible<Callback, Callback&&>::value)
-> detail::scope_guard<Callback>
-> detail::scope_guard<Callback, exit_type>
{
return detail::scope_guard<Callback>{std::forward<Callback>(callback)};
return detail::scope_guard<Callback, exit_type>{std::forward<Callback>(callback)};
}

#endif /* SCOPE_GUARD_HPP_ */