#ifndef FINALLY_H
#define FINALLY_H
#include <utility>
#include <type_traits>
#include "NonCopyable.h"
#include "Utilities.h"
///
/// Runs some code when the current scope is left
///
/// This is a generic form of a pattern commonly used to ensure an aquired resource is released
/// when exiting the current scope. Examples of this are the lock_guard class for mutexes.
///
/// Idea comes from ScopeGuard11 at about 1:05 in to the presentation here:
/// http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C
///
template<typename Functor>
struct Finalizer : private NonCopyable
{
Finalizer() = delete;
Finalizer(Functor func) : m_func(std::move(func)), m_active(true) {}
Finalizer(Finalizer&& rhs) : m_func(std::move(rhs.m_func)), m_active(rhs.m_active) { rhs.dismiss(); }
~Finalizer() { if (m_active) m_func(); }
void dismiss() { m_active = false; }
private:
Functor m_func;
bool m_active;
};
template<typename Functor>
Finalizer<Functor> makeFinalizer(Functor func)
{
return Finalizer<Functor>(std::move(func));
}
namespace detail
{
enum class FinalizerDummyClass {};
template<typename Functor>
Finalizer<Functor> operator+(FinalizerDummyClass, Functor&& fn) {
return Finalizer<Functor>(std::forward<Functor>(fn));
}
}
//
// http://stackoverflow.com/questions/10270328/the-simplest-and-neatest-c11-scopeguard
//
#define FINALIZE_IF_NOT_COMMITED(finalizerName) auto TOKENPASTE(finalizer_,finalizerName) = ::detail::FinalizerDummyClass() + [&]()
#define FINALIZE_COMMIT(finalizerName) TOKENPASTE(finalizer_,finalizerName).dismiss();
#define finally FINALIZE_IF_NOT_COMMITED(__LINE__)
#define finally_inline(expr) auto ANONYMOUS_VARIABLE(finalizerObj_) = makeFinalizer( [&]{ expr } );
/*
Example usage:
int main(int argc, char* argv[])
{
std::mutex m;
m.lock();
finally { m.unlock(); }; // will be always executed on exit from the scope
finally_inline( printf("goodbye!\n"); );
finally { printf("goodbye!\n"); };
finally
{
// This will be run when the end of main is reached
MessageBoxA(NULL, "About to Exit", "Exiting", MB_OK);
};
// ...
DBTransaction transaction;
transaction.Begin();
FINALIZE_IF_NOT_COMMITED(DBTransactionName)
{
transaction.Cancel(); //will be executed on exit from the scope, in case finalizer is not commited by FINALIZE_COMMIT(DBTransactionName)
};
//...
//Any exit from scope here will trigger the FINILIZE_IF_NOT_COMMITED block executed
//...
return -1;
FINALIZE_COMMIT(DBTransactionName)
{
transaction.Commit(); //the code executed immediately and execution of FINALIZE_IF_NOT_COMMITED block is cancelled
};
return 0;
}
*/
/*
///
/// Original idea comes from here:
/// http://stackoverflow.com/questions/8903911/is-it-possible-to-avoid-copying-lambda-functor-in-this-situation
/// However not sure how reliable this particular implementation is. It potentially calls more than once or generates extra code
///
template<typename Functor>
struct DodgyFinalizer : private NonCopyable
{
DodgyFinalizer(Functor&& func) : m_func(std::forward<Functor>(func)), m_isMoved(false) {}
DodgyFinalizer(DodgyFinalizer&& other) : m_func(std::move(other.m_func)), m_isMoved(false) { other.m_isMoved = true; }
~DodgyFinalizer() { if (!m_isMoved) m_func(); }
private:
Functor m_func;
mutable bool m_isMoved;
};
template<typename Functor>
DodgyFinalizer<Functor> dodgyFinally(Functor&& func)
{
return DodgyFinalizer<Functor>(std::forward<Functor>(func));
}
*/
/*
//
// The problem and proposed type of desired interface presented in the video
//
// single
(action)
auto g1 = scopeGuard([]{ (cleanup) });
auto g2 = scopeGuard([]{ (rollback) });
(next)
g2.dismiss();
//composed
(action1)
auto g1 = scopeGuard([]{ (cleanup1) });
auto g2 = scopeGuard([]{ (rollback1) });
(action2)
auto g3 = scopeGuard([]{ (cleanup2) });
auto g4 = scopeGuard([]{ (rollback2) });
(next2)
g2.dismiss();
g4.dismiss();
SCOPE_EXIT { (cleanup) };
//
// Pretty close to the original solution code as presented in the video
//
template <class Fun>
class ScopeGuard {
Fun f;
bool active;
public:
ScopeGuard(Fun f) : f(std::move(f)), active(true) {}
~ScopeGuard() { if (active) f(); }
void dismiss() { active = false; }
ScopeGuard() = delete;
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
rhs.dismiss();
}
};
template<typename Functor>
ScopeGuard<Functor> scopeGuard(Functor func)
{
return ScopeGuard<Functor>(std::move(func));
}
namespace detail {
enum class ScopeGuardOnExit {};
template <typename Fun>
ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn) {
return ScopeGuard<Fun>(std::forward<Fun>(fn));
}
}
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = ::detail::ScopeGuardOnExit() + [&]()
//
// example
//
void fun()
{
char name[] = "/tmp/deleteme.XXXXXX";
auto fd = mkstemp(name);
SCOPE_EXIT{ fclose(fd); unlink(name); };
auto buf = malloc(1024 * 1024);
SCOPE_EXIT{ free(buf); };
// ... use fd and buf ...
}
*/
#endif // FINALLY_H