Skip to content

Instantly share code, notes, and snippets.

@kingsamchen
Created December 13, 2020 14:37
Show Gist options
  • Save kingsamchen/187f00b4a9389370d6b608d7f3c26c60 to your computer and use it in GitHub Desktop.
Save kingsamchen/187f00b4a9389370d6b608d7f3c26c60 to your computer and use it in GitHub Desktop.
#pragma once
#include <exception>
#include <type_traits>
#include <utility>
namespace folly {
namespace detail {
class ScopeGuardImplBase {
public:
void dismiss() noexcept { dismissed_ = true; }
protected:
ScopeGuardImplBase() noexcept
: dismissed_(false) {}
static void warnAboutToCrash() noexcept;
static ScopeGuardImplBase makeEmptyScopeGuard() noexcept
{
return ScopeGuardImplBase {};
}
template<typename T>
static const T& asConst(const T& t) noexcept
{
return t;
}
bool dismissed_;
};
template<typename FunctionType, bool InvokeNoexcept>
class ScopeGuardImpl : public ScopeGuardImplBase {
public:
//explicit ScopeGuardImpl(FunctionType& fn) noexcept(
// std::is_nothrow_copy_constructible<FunctionType>::value)
// : ScopeGuardImpl(
// asConst(fn),
// makeFailsafe(
// std::is_nothrow_copy_constructible<FunctionType> {},
// &fn)) {}
explicit ScopeGuardImpl(const FunctionType& fn) noexcept(
std::is_nothrow_copy_constructible<FunctionType>::value)
: ScopeGuardImpl(
fn,
makeFailsafe(
std::is_nothrow_copy_constructible<FunctionType> {},
&fn)) {}
explicit ScopeGuardImpl(FunctionType&& fn) noexcept(
std::is_nothrow_move_constructible<FunctionType>::value)
: ScopeGuardImpl(
std::move_if_noexcept(fn),
makeFailsafe(
std::is_nothrow_move_constructible<FunctionType> {},
&fn)) {}
ScopeGuardImpl(ScopeGuardImpl&& other) noexcept(
std::is_nothrow_move_constructible<FunctionType>::value)
: function_(std::move_if_noexcept(other.function_))
{
// If the above line attempts a copy and the copy throws, other is
// left owning the cleanup action and will execute it (or not) depending
// on the value of other.dismissed_. The following lines only execute
// if the move/copy succeeded, in which case *this assumes ownership of
// the cleanup action and dismisses other.
dismissed_ = std::exchange(other.dismissed_, true);
}
~ScopeGuardImpl() noexcept(InvokeNoexcept)
{
if (!dismissed_) {
execute();
}
}
private:
static ScopeGuardImplBase makeFailsafe(std::true_type, const void*) noexcept
{
return makeEmptyScopeGuard();
}
template<typename Fn>
static auto makeFailsafe(std::false_type, Fn* fn) noexcept
-> ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept>
{
return ScopeGuardImpl<decltype(std::ref(*fn)), InvokeNoexcept> {
std::ref(*fn)
};
}
template<typename Fn>
explicit ScopeGuardImpl(Fn&& fn, ScopeGuardImplBase&& failsafe)
: ScopeGuardImplBase {}, function_(std::forward<Fn>(fn))
{
//failsafe.dismiss();
}
void* operator new(std::size_t) = delete;
void execute() noexcept(InvokeNoexcept)
{
if (InvokeNoexcept) {
using R = decltype(function_());
auto catcher = []() -> R { warnAboutToCrash(), std::terminate(); };
function_();
//catch_exception(function_, catcher);
} else {
function_();
}
}
FunctionType function_;
};
template<typename F, bool INE>
using ScopeGuardImplDecay = ScopeGuardImpl<typename std::decay<F>::type, INE>;
} // namespace detail
} // namespace folly
#include <iostream>
#include <string>
#include <functional>
#include "folly_scoped_guard.h"
int main()
{
std::function<void()> cb([] { std::cout << "inside std::function<void()>\n"; });
const std::function<void()> ccb([]{ std::cout << "inside std::function<void()>\n"; });
std::string s = "test";
auto mcb = [s]() mutable {
s += "fuck";
std::cout << "inside mutable lambda -- " << s << "\n";
};
//folly::detail::ScopeGuardImpl<decltype(cb), true> guard(cb);
folly::detail::ScopeGuardImpl<decltype(mcb), true> guard2(mcb);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment