Newer
Older
Import / applications / MakePDF / Framework / Finally.h
#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