memgraph/include/utils/auto_scope.hpp

66 lines
1.6 KiB
C++
Raw Normal View History

#pragma once
2015-10-09 07:24:12 +08:00
#include <utility>
/**
* @brief Calls a cleanup function on scope exit
2015-10-09 07:24:12 +08:00
*
* consider this example:
2015-10-09 07:24:12 +08:00
*
* void hard_worker()
* {
* resource.enable();
* do_stuff(); // throws exception
* resource.disable();
* }
2015-10-09 07:24:12 +08:00
*
* if do_stuff throws an exception, resource.disable is never called
* and the app is left in an inconsistent state. ideally, you would like
* to call resource.disable regardles of the exception being thrown.
* OnScopeExit makes this possible and very convenient via a 'Auto' macro
2015-12-08 04:50:07 +08:00
*
* void hard_worker()
* {
* resource.enable();
* Auto(resource.disable());
* do_stuff(); // throws exception
* }
2015-10-09 07:24:12 +08:00
*
* now, resource.disable will be called every time it goes out of scope
* regardless of the exception
2015-10-09 07:24:12 +08:00
*
* @tparam F Lambda which holds a wrapper function around the cleanup code
2015-10-09 07:24:12 +08:00
*/
template <class F>
class OnScopeExit
{
public:
OnScopeExit(F& f) : f(f) {}
~OnScopeExit()
{
// calls the cleanup function
f();
}
private:
F& f;
};
#define TOKEN_PASTEx(x, y) x##y
#define TOKEN_PASTE(x, y) TOKEN_PASTEx(x, y)
#define Auto_INTERNAL(Destructor, counter) \
auto TOKEN_PASTE(auto_func_, counter) = [&]() { Destructor; }; \
OnScopeExit<decltype(TOKEN_PASTE(auto_func_, counter))> \
TOKEN_PASTE(auto_, counter)(TOKEN_PASTE(auto_func_, counter));
#define Auto(Destructor) Auto_INTERNAL(Destructor, __COUNTER__)
// -- example:
// Auto(f());
// -- is expended to:
// auto auto_func_1 = [&]() { f(); };
// OnScopeExit<decltype(auto_func_1)> auto_1(auto_func_1);
// -- f() is called at the end of a scope