//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2000 Andrei Alexandrescu // Copyright (c) 2000 Petru Marginean // Copyright (c) 2005 Joshua Lehrer // // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author makes no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_SCOPEGUARD_H_ #define LOKI_SCOPEGUARD_H_ #include #include "mongo/platform/compiler.h" namespace mongo { //////////////////////////////////////////////////////////////////////////////// /// \class RefToValue /// /// Transports a reference as a value /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard //////////////////////////////////////////////////////////////////////////////// template class RefToValue { public: RefToValue(T& ref) : ref_(ref) {} RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) {} operator T&() const { return ref_; } private: // Disable - not implemented RefToValue(); RefToValue& operator=(const RefToValue&); T& ref_; }; //////////////////////////////////////////////////////////////////////////////// /// RefToValue creator. //////////////////////////////////////////////////////////////////////////////// template inline RefToValue ByRef(T& t) { return RefToValue(t); } //////////////////////////////////////////// /// ScopeGuard /* Trivial example for use: FILE* f = fopen("myfile.txt", "w+"); if (!f) return error; ON_BLOCK_EXIT(fclose, f); More complicated example: ScopeGuard guard = MakeGuard(my_rollback_func, myparam); ... if (successful) { guard.Dismiss(); return; } // guard is still active here and will fire at scope exit ... */ class ScopeGuardImplBase { ScopeGuardImplBase& operator=(const ScopeGuardImplBase&); protected: ~ScopeGuardImplBase() {} ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() : dismissed_(other.dismissed_) { other.Dismiss(); } template static void SafeExecute(J& j) throw() { if (!j.dismissed_) try { j.Execute(); } catch (...) { std::terminate(); } } mutable bool dismissed_; public: ScopeGuardImplBase() throw() : dismissed_(false) {} void Dismiss() const throw() { dismissed_ = true; } }; //////////////////////////////////////////////////////////////// /// /// \typedef typedef const ScopeGuardImplBase& ScopeGuard /// /// See Andrei's and Petru Marginean's CUJ article /// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm /// /// Changes to the original code by Joshua Lehrer: /// http://www.lehrerfamily.com/scopeguard.html //////////////////////////////////////////////////////////////// typedef const ScopeGuardImplBase& ScopeGuard; template class ScopeGuardImpl0 : public ScopeGuardImplBase { public: static ScopeGuardImpl0 MakeGuard(F fun) { return ScopeGuardImpl0(fun); } ~ScopeGuardImpl0() throw() { SafeExecute(*this); } void Execute() { fun_(); } protected: ScopeGuardImpl0(F fun) : fun_(fun) {} F fun_; }; template inline ScopeGuardImpl0 MakeGuard(F fun) { return ScopeGuardImpl0::MakeGuard(fun); } template class ScopeGuardImpl1 : public ScopeGuardImplBase { public: static ScopeGuardImpl1 MakeGuard(F fun, P1 p1) { return ScopeGuardImpl1(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 inline ScopeGuardImpl1 MakeGuard(F fun, P1 p1) { return ScopeGuardImpl1::MakeGuard(fun, p1); } template class ScopeGuardImpl2 : public ScopeGuardImplBase { public: static ScopeGuardImpl2 MakeGuard(F fun, P1 p1, P2 p2) { return ScopeGuardImpl2(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 inline ScopeGuardImpl2 MakeGuard(F fun, P1 p1, P2 p2) { return ScopeGuardImpl2::MakeGuard(fun, p1, p2); } template class ScopeGuardImpl3 : public ScopeGuardImplBase { public: static ScopeGuardImpl3 MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { return ScopeGuardImpl3(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 inline ScopeGuardImpl3 MakeGuard(F fun, P1 p1, P2 p2, P3 p3) { return ScopeGuardImpl3::MakeGuard(fun, p1, p2, p3); } //************************************************************ template class ObjScopeGuardImpl0 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl0 MakeObjGuard(Obj& obj, MemFun memFun) { return ObjScopeGuardImpl0(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 inline ObjScopeGuardImpl0 MakeObjGuard(Obj& obj, MemFun memFun) { return ObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } template inline ObjScopeGuardImpl0 MakeGuard(Ret (Obj2::*memFun)(), Obj1& obj) { return ObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } template inline ObjScopeGuardImpl0 MakeGuard(Ret (Obj2::*memFun)(), Obj1* obj) { return ObjScopeGuardImpl0::MakeObjGuard(*obj, memFun); } template class ObjScopeGuardImpl1 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl1 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { return ObjScopeGuardImpl1(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 inline ObjScopeGuardImpl1 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { return ObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } template inline ObjScopeGuardImpl1 MakeGuard(Ret (Obj2::*memFun)(P1a), Obj1& obj, P1b p1) { return ObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } template inline ObjScopeGuardImpl1 MakeGuard(Ret (Obj2::*memFun)(P1a), Obj1* obj, P1b p1) { return ObjScopeGuardImpl1::MakeObjGuard(*obj, memFun, p1); } template class ObjScopeGuardImpl2 : public ScopeGuardImplBase { public: static ObjScopeGuardImpl2 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { return ObjScopeGuardImpl2(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 inline ObjScopeGuardImpl2 MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { return ObjScopeGuardImpl2::MakeObjGuard(obj, memFun, p1, p2); } template inline ObjScopeGuardImpl2 MakeGuard( Ret (Obj2::*memFun)(P1a, P2a), Obj1& obj, P1b p1, P2b p2) { return ObjScopeGuardImpl2::MakeObjGuard( obj, memFun, p1, p2); } template inline ObjScopeGuardImpl2 MakeGuard( Ret (Obj2::*memFun)(P1a, P2a), Obj1* obj, P1b p1, P2b p2) { return ObjScopeGuardImpl2::MakeObjGuard( *obj, memFun, p1, p2); } } // namespace Loki #define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2 #define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2) #define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__) #define ON_BLOCK_EXIT \ MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard #define ON_BLOCK_EXIT_OBJ \ MONGO_COMPILER_VARIABLE_UNUSED ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard #endif // LOKI_SCOPEGUARD_H_