Last active
June 8, 2022 14:07
-
-
Save Trass3r/530e0d91601c5051e3bc2fb94d95fbc9 to your computer and use it in GitHub Desktop.
D scope guards emulation for C++17 -- https://godbolt.org/g/Vknqur https://godbolt.org/z/nFv3LS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Copyright (C) 2017-2018 Andreas Hollandt | |
* | |
* Distributed under the Boost Software License, Version 1.0. | |
* See copy at http://boost.org/LICENSE_1_0.txt. | |
*/ | |
#pragma once | |
#include <exception> | |
#include <utility> // forward, move | |
#if _MSC_VER && _MSC_VER < 1914 | |
#error update VS | |
#endif | |
// e.g. gcc 7+ with -std=c++17 | |
#if !_MSC_VER && __EXCEPTIONS && !__cpp_lib_uncaught_exceptions | |
#error C++17 uncaught_exceptions support required | |
#endif | |
#if _MSC_VER | |
#define SUPPRESS_UNUSED_WARNING __pragma(warning(suppress : 4189)) | |
#define SUPPRESS_CONST_CONDITION __pragma(warning(suppress : 4127)) | |
#define ALWAYS_INLINE __forceinline | |
#else | |
#define SUPPRESS_UNUSED_WARNING [[gnu::unused]] | |
#define SUPPRESS_CONST_CONDITION | |
#define ALWAYS_INLINE [[gnu::always_inline]] | |
#endif | |
#define SCOPEGUARDCONCAT2(x, y) x ## y | |
#define SCOPEGUARDCONCAT(x, y) SCOPEGUARDCONCAT2(x, y) | |
//! main macro | |
#define scope(stype) SUPPRESS_UNUSED_WARNING auto&& SCOPEGUARDCONCAT(scopeguard, __LINE__) = \ | |
ScopeGuardForw<ScopeGuardType::stype>() ^ [&]() | |
//! the possible arguments for scope() | |
enum class ScopeGuardType { exit, failure, success }; | |
template <ScopeGuardType stype> | |
struct UncaughtExceptionsTracker | |
{ | |
#if __EXCEPTIONS || _CPPUNWIND | |
int baseline = std::uncaught_exceptions(); | |
bool exraised() const | |
{ | |
return std::uncaught_exceptions() > baseline; | |
} | |
#else | |
static bool exraised() { return false; } | |
#endif | |
}; | |
// empty base class optimization | |
template<> | |
struct UncaughtExceptionsTracker<ScopeGuardType::exit> | |
{ | |
static bool exraised() { return false; } | |
}; | |
//! main RAII guard class | |
template<ScopeGuardType stype, typename F> | |
struct ScopeGuard final : UncaughtExceptionsTracker<stype> | |
{ | |
F f; | |
ALWAYS_INLINE | |
ScopeGuard(F&& f) : f(std::move(f)) {} | |
ALWAYS_INLINE | |
~ScopeGuard() noexcept | |
{ | |
SUPPRESS_CONST_CONDITION | |
if (stype == ScopeGuardType::exit || | |
(this->exraised() == (stype == ScopeGuardType::failure))) | |
f(); | |
} | |
ScopeGuard(const ScopeGuard&) = delete; | |
ScopeGuard(ScopeGuard&&) = delete; | |
void operator=(const ScopeGuard&) = delete; | |
void operator=(ScopeGuard&&) = delete; | |
}; | |
// enables the lambda to be naturally specified after the scope() part | |
template <ScopeGuardType stype> | |
struct ScopeGuardForw | |
{ | |
template <typename F> | |
ALWAYS_INLINE | |
ScopeGuard<stype, F> | |
operator^(F&& f) const | |
{ | |
return { std::forward<F>(f) }; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "scopeguard.h" | |
#include <cstdio> | |
auto foo() | |
{ | |
auto f = new int(5); | |
scope(exit) | |
{ | |
delete f; | |
}; | |
scope(failure) | |
{ | |
puts("it failed"); | |
}; | |
return *f; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment