Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
20 changes: 18 additions & 2 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 All @@ -21,16 +22,31 @@ jobs:
- os: ubuntu-latest
compiler: g++-11
install: g++-11
- os: ubuntu-latest
compiler: g++-14
install: g++-14
extra_build_flags: -DENABLE_COVERAGE:BOOL=ON # coverage build
- os: ubuntu-20.04
compiler: clang++-7
install: clang-7
- os: ubuntu-latest
- os: ubuntu-21.04
compiler: clang++-12
- os: ubuntu-latest
install: clang-12
- os: ubuntu-21.04
compiler: clang++-13
install: clang-13
- os: ubuntu-latest
compiler: clang++-14
install: clang-14
- os: ubuntu-latest
compiler: clang++-15
install: clang-15
- os: ubuntu-latest
compiler: clang++-16
install: clang-16
- os: ubuntu-latest
compiler: clang++-18
install: clang-18
- os: macos-11
compiler: g++-10
- os: macos-latest
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_ */