64 lines
1.5 KiB
C++
64 lines
1.5 KiB
C++
#pragma once
|
|
|
|
#include <utility> // std::forward, std::move
|
|
#include <algorithm> // std::swap
|
|
#include <type_traits> // std::decay
|
|
|
|
namespace ipc {
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
/// Execute guard function when the enclosing scope exits
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
template <typename F>
|
|
class scope_guard {
|
|
F destructor_;
|
|
mutable bool dismiss_;
|
|
|
|
public:
|
|
template <typename D>
|
|
scope_guard(D && destructor)
|
|
: destructor_(std::forward<D>(destructor))
|
|
, dismiss_(false) {
|
|
}
|
|
|
|
scope_guard(scope_guard&& rhs)
|
|
: destructor_(std::move(rhs.destructor_))
|
|
, dismiss_(true) /* dismiss rhs */ {
|
|
std::swap(dismiss_, rhs.dismiss_);
|
|
}
|
|
|
|
~scope_guard() {
|
|
try { do_exit(); }
|
|
/**
|
|
* In the realm of exceptions, it is fundamental that you can do nothing
|
|
* if your "undo/recover" action fails.
|
|
*/
|
|
catch (...) { /* Do nothing */ }
|
|
}
|
|
|
|
void swap(scope_guard & rhs) {
|
|
std::swap(destructor_, rhs.destructor_);
|
|
std::swap(dismiss_ , rhs.dismiss_);
|
|
}
|
|
|
|
void dismiss() const noexcept {
|
|
dismiss_ = true;
|
|
}
|
|
|
|
void do_exit() {
|
|
if (!dismiss_) {
|
|
dismiss_ = true;
|
|
destructor_();
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename D>
|
|
constexpr auto guard(D && destructor) noexcept {
|
|
return scope_guard<std::decay_t<D>> {
|
|
std::forward<D>(destructor)
|
|
};
|
|
}
|
|
|
|
} // namespace ipc
|