Skip to content

Instantly share code, notes, and snippets.

@Trass3r
Last active June 8, 2022 14:07
Show Gist options
  • Save Trass3r/530e0d91601c5051e3bc2fb94d95fbc9 to your computer and use it in GitHub Desktop.
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
/*!
* 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) };
}
};
#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