blob: 326dc0c32c7a0f4ad714863670c4fb44c002b034 [file] [log] [blame]
//
// Author: Andrei Alexandrescu - andrei@metalanguage.com
//
// The code below is based on the following article published in
// C/C++ Users Journal by Andrei Alexandrescu:
//
// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm
//
// ScopeGuard is useful when you need to perform automatic cleanup of resources.
// This idiom is important when you want to assemble an operation out of several
// atomic operations, each of which could fail.
//
// Usage
// ------
// Scope guard for objects:
// void f(T& t) {
// std::vector<T> v;
// v.push_back(t);
// ScopeGuard guard = MakeObjGuard(v, &std::vector<T>v::pop_back);
// if (!Commit()) {
// return;
// }
// guard.Dismiss(); // removes the t from the vector in the case Commit fails
// }
//
// Scope guard for functions:
// void open();
// void close(int i);
// void g(int i) {
// open();
// ScopeGuard guard = MakeGuard(close, 0);
// if (!read()) {
// return;
// }
// if (!write()) {
// return;
// }
// }
//
// Using the macros:
// void g(int i) {
// open();
// ON_SCOPE_EXIT(close, 0);
// if (!read()) {
// return;
// }
// if (!write()) {
// return;
// }
// }
// TODO(omaha): provide support to run with or without exceptions enabled.
// For now it assumes that the code is not throwing exceptions.
#ifndef SCOPEGUARD_H_
#define SCOPEGUARD_H_
namespace omaha {
template <class T>
class RefHolder
{
T& ref_;
public:
RefHolder(T& ref) : ref_(ref) {}
operator T& () const
{
return ref_;
}
private:
// Disable assignment - not implemented
RefHolder& operator=(const RefHolder&);
};
template <class T>
inline RefHolder<T> ByRef(T& t)
{
return RefHolder<T>(t);
}
class ScopeGuardImplBase
{
ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
protected:
~ScopeGuardImplBase()
{
}
ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
: dismissed_(other.dismissed_)
{
other.Dismiss();
}
template <typename J>
static void SafeExecute(J& j) throw()
{
if (!j.dismissed_)
{
// TODO(omaha): assume this does not throw
j.Execute();
}
}
mutable bool dismissed_;
public:
ScopeGuardImplBase() throw() : dismissed_(false)
{
}
void Dismiss() const throw()
{
dismissed_ = true;
}
};
typedef const ScopeGuardImplBase& ScopeGuard;
template <typename F>
class ScopeGuardImpl0 : public ScopeGuardImplBase
{
public:
static ScopeGuardImpl0<F> MakeGuard(F fun)
{
return ScopeGuardImpl0<F>(fun);
}
~ScopeGuardImpl0() throw()
{
SafeExecute(*this);
}
void Execute()
{
fun_();
}
protected:
ScopeGuardImpl0(F fun) : fun_(fun)
{
}
F fun_;
};
template <typename F>
inline ScopeGuardImpl0<F> MakeGuard(F fun)
{
return ScopeGuardImpl0<F>::MakeGuard(fun);
}
template <typename F, typename P1>
class ScopeGuardImpl1 : public ScopeGuardImplBase
{
public:
static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
{
return ScopeGuardImpl1<F, P1>(fun, p1);
}
~ScopeGuardImpl1() throw()
{
SafeExecute(*this);
}
void Execute()
{
fun_(p1_);
}
protected:
ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
{
}
F fun_;
const P1 p1_;
};
template <typename F, typename P1>
inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
{
return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
}
template <typename F, typename P1, typename P2>
class ScopeGuardImpl2: public ScopeGuardImplBase
{
public:
static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
{
return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2);
}
~ScopeGuardImpl2() throw()
{
SafeExecute(*this);
}
void Execute()
{
fun_(p1_, p2_);
}
protected:
ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2)
{
}
F fun_;
const P1 p1_;
const P2 p2_;
};
template <typename F, typename P1, typename P2>
inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
{
return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2);
}
template <typename F, typename P1, typename P2, typename P3>
class ScopeGuardImpl3 : public ScopeGuardImplBase
{
public:
static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
{
return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3);
}
~ScopeGuardImpl3() throw()
{
SafeExecute(*this);
}
void Execute()
{
fun_(p1_, p2_, p3_);
}
protected:
ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3)
{
}
F fun_;
const P1 p1_;
const P2 p2_;
const P3 p3_;
};
template <typename F, typename P1, typename P2, typename P3>
inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
{
return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3);
}
template <class Obj, typename MemFun>
class ObjScopeGuardImpl0 : public ScopeGuardImplBase
{
public:
static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
{
return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun);
}
~ObjScopeGuardImpl0() throw()
{
SafeExecute(*this);
}
void Execute()
{
(obj_.*memFun_)();
}
protected:
ObjScopeGuardImpl0(Obj& obj, MemFun memFun)
: obj_(obj), memFun_(memFun) {}
Obj& obj_;
MemFun memFun_;
};
template <class Obj, typename MemFun>
inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
{
return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun);
}
template <class Obj, typename MemFun, typename P1>
class ObjScopeGuardImpl1 : public ScopeGuardImplBase
{
public:
static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
{
return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1);
}
~ObjScopeGuardImpl1() throw()
{
SafeExecute(*this);
}
void Execute()
{
(obj_.*memFun_)(p1_);
}
protected:
ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1)
: obj_(obj), memFun_(memFun), p1_(p1) {}
Obj& obj_;
MemFun memFun_;
const P1 p1_;
};
template <class Obj, typename MemFun, typename P1>
inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
{
return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1);
}
template <class Obj, typename MemFun, typename P1, typename P2>
class ObjScopeGuardImpl2 : public ScopeGuardImplBase
{
public:
static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
{
return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2);
}
~ObjScopeGuardImpl2() throw()
{
SafeExecute(*this);
}
void Execute()
{
(obj_.*memFun_)(p1_, p2_);
}
protected:
ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2)
: obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {}
Obj& obj_;
MemFun memFun_;
const P1 p1_;
const P2 p2_;
};
template <class Obj, typename MemFun, typename P1, typename P2>
inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
{
return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2);
}
#define CONCATENATE_DIRECT(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
#define ON_SCOPE_EXIT ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard
#define ON_SCOPE_EXIT_OBJ ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard
} // namespace omaha
#endif //SCOPEGUARD_H_