X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/655719367ac5e131d9642e5783f3ecf64d1a3385..784ee7d511ddec88c2a53c1b50c85850eb341dc6:/include/wx/scopeguard.h diff --git a/include/wx/scopeguard.h b/include/wx/scopeguard.h index 21719fb017..45fe82f5bf 100644 --- a/include/wx/scopeguard.h +++ b/include/wx/scopeguard.h @@ -11,8 +11,9 @@ /* Acknowledgements: this header is heavily based on (well, almost the exact - copy of) wxScopeGuard.h by Andrei Alexandrescu and Petru Marginean published + copy of) ScopeGuard.h by Andrei Alexandrescu and Petru Marginean published in December 2000 issue of C/C++ Users Journal. + http://www.cuj.com/documents/cujcexp1812alexandr/ */ #ifndef _WX_SCOPEGUARD_H_ @@ -26,13 +27,46 @@ // helpers // ---------------------------------------------------------------------------- +#ifdef __WATCOMC__ + +// WATCOM-FIXME: C++ of Open Watcom 1.3 doesn't like OnScopeExit() created +// through template so it must be workarounded with dedicated inlined macro. +// For compatibility with Watcom compilers wxPrivate::OnScopeExit must be +// replaced with wxPrivateOnScopeExit but in user code (for everyone who +// doesn't care about OW compatibility) wxPrivate::OnScopeExit still works. + +#define wxPrivateOnScopeExit(guard) \ + { \ + if ( !(guard).WasDismissed() ) \ + { \ + wxTRY \ + { \ + (guard).Execute(); \ + } \ + wxCATCH_ALL(;) \ + } \ + } + +#define wxPrivateUse(n) wxUnusedVar(n) + +#else + +// namespace support was first implemented in gcc-2.95, +// so avoid using it for older versions. +#if !defined(__GNUC__) || wxCHECK_GCC_VERSION(2, 95) + +#define wxHAS_NAMESPACES + namespace wxPrivate { +#else +#define wxPrivate +#endif // in the original implementation this was a member template function of // ScopeGuardImplBase but gcc 2.8 which is still used for OS/2 doesn't // support member templates and so we must make it global - template - void OnScopeExit(ScopeGuardImpl& guard) + template + void OnScopeExit(ScopeGuardImpl& guard) { if ( !guard.WasDismissed() ) { @@ -46,12 +80,19 @@ namespace wxPrivate } // just to avoid the warning about unused variables - template + template void Use(const T& WXUNUSED(t)) { } +#if !defined(__GNUC__) || wxCHECK_GCC_VERSION(2, 95) } // namespace wxPrivate - +#endif + +#define wxPrivateOnScopeExit(n) wxPrivate::OnScopeExit(n) +#define wxPrivateUse(n) wxPrivate::Use(n) + +#endif + // ============================================================================ // wxScopeGuard for functions and functors // ============================================================================ @@ -65,20 +106,20 @@ class wxScopeGuardImplBase public: wxScopeGuardImplBase() : m_wasDismissed(false) { } + wxScopeGuardImplBase(const wxScopeGuardImplBase& other) + : m_wasDismissed(other.m_wasDismissed) + { + other.Dismiss(); + } + void Dismiss() const { m_wasDismissed = true; } - // for OnScopeExit() only we can't make it friend, unfortunately)! + // for OnScopeExit() only (we can't make it friend, unfortunately)! bool WasDismissed() const { return m_wasDismissed; } protected: ~wxScopeGuardImplBase() { } - wxScopeGuardImplBase(const wxScopeGuardImplBase& other) - : m_wasDismissed(other.m_wasDismissed) - { - other.Dismiss(); - } - // must be mutable for copy ctor to work mutable bool m_wasDismissed; @@ -86,11 +127,14 @@ private: wxScopeGuardImplBase& operator=(const wxScopeGuardImplBase&); }; +// wxScopeGuard is just a reference, see the explanation in CUJ article +typedef const wxScopeGuardImplBase& wxScopeGuard; + // ---------------------------------------------------------------------------- // wxScopeGuardImpl0: scope guard for actions without parameters // ---------------------------------------------------------------------------- -template +template class wxScopeGuardImpl0 : public wxScopeGuardImplBase { public: @@ -99,7 +143,7 @@ public: return wxScopeGuardImpl0(fun); } - ~wxScopeGuardImpl0() { wxPrivate::OnScopeExit(*this); } + ~wxScopeGuardImpl0() { wxPrivateOnScopeExit(*this); } void Execute() { m_fun(); } @@ -111,7 +155,7 @@ protected: wxScopeGuardImpl0& operator=(const wxScopeGuardImpl0&); }; -template +template inline wxScopeGuardImpl0 wxMakeGuard(F fun) { return wxScopeGuardImpl0::MakeGuard(fun); @@ -121,7 +165,7 @@ inline wxScopeGuardImpl0 wxMakeGuard(F fun) // wxScopeGuardImpl1: scope guard for actions with 1 parameter // ---------------------------------------------------------------------------- -template +template class wxScopeGuardImpl1 : public wxScopeGuardImplBase { public: @@ -130,7 +174,7 @@ public: return wxScopeGuardImpl1(fun, p1); } - ~wxScopeGuardImpl1() { wxPrivate::OnScopeExit(*this); } + ~wxScopeGuardImpl1() { wxPrivateOnScopeExit(* this); } void Execute() { m_fun(m_p1); } @@ -143,7 +187,7 @@ protected: wxScopeGuardImpl1& operator=(const wxScopeGuardImpl1&); }; -template +template inline wxScopeGuardImpl1 wxMakeGuard(F fun, P1 p1) { return wxScopeGuardImpl1::MakeGuard(fun, p1); @@ -153,7 +197,7 @@ inline wxScopeGuardImpl1 wxMakeGuard(F fun, P1 p1) // wxScopeGuardImpl2: scope guard for actions with 2 parameters // ---------------------------------------------------------------------------- -template +template class wxScopeGuardImpl2 : public wxScopeGuardImplBase { public: @@ -162,7 +206,7 @@ public: return wxScopeGuardImpl2(fun, p1, p2); } - ~wxScopeGuardImpl2() { wxPrivate::OnScopeExit(*this); } + ~wxScopeGuardImpl2() { wxPrivateOnScopeExit(*this); } void Execute() { m_fun(m_p1, m_p2); } @@ -176,7 +220,7 @@ protected: wxScopeGuardImpl2& operator=(const wxScopeGuardImpl2&); }; -template +template inline wxScopeGuardImpl2 wxMakeGuard(F fun, P1 p1, P2 p2) { return wxScopeGuardImpl2::MakeGuard(fun, p1, p2); @@ -190,7 +234,7 @@ inline wxScopeGuardImpl2 wxMakeGuard(F fun, P1 p1, P2 p2) // wxObjScopeGuardImpl0 // ---------------------------------------------------------------------------- -template +template class wxObjScopeGuardImpl0 : public wxScopeGuardImplBase { public: @@ -200,7 +244,7 @@ public: return wxObjScopeGuardImpl0(obj, memFun); } - ~wxObjScopeGuardImpl0() { wxPrivate::OnScopeExit(*this); } + ~wxObjScopeGuardImpl0() { wxPrivateOnScopeExit(*this); } void Execute() { (m_obj.*m_memfun)(); } @@ -212,13 +256,13 @@ protected: MemFun m_memfun; }; -template +template inline wxObjScopeGuardImpl0 wxMakeObjGuard(Obj& obj, MemFun memFun) { return wxObjScopeGuardImpl0::MakeObjGuard(obj, memFun); } -template +template class wxObjScopeGuardImpl1 : public wxScopeGuardImplBase { public: @@ -228,12 +272,12 @@ public: return wxObjScopeGuardImpl1(obj, memFun, p1); } - ~wxObjScopeGuardImpl1() { wxPrivate::OnScopeExit(*this); } + ~wxObjScopeGuardImpl1() { wxPrivateOnScopeExit(*this); } void Execute() { (m_obj.*m_memfun)(m_p1); } protected: - wxObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) + wxObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : m_obj(obj), m_memfun(memFun), m_p1(p1) { } Obj& m_obj; @@ -241,14 +285,14 @@ protected: const P1 m_p1; }; -template +template inline wxObjScopeGuardImpl1 wxMakeObjGuard(Obj& obj, MemFun memFun, P1 p1) { return wxObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); } -template +template class wxObjScopeGuardImpl2 : public wxScopeGuardImplBase { public: @@ -258,12 +302,12 @@ public: return wxObjScopeGuardImpl2(obj, memFun, p1, p2); } - ~wxObjScopeGuardImpl2() { wxPrivate::OnScopeExit(*this); } + ~wxObjScopeGuardImpl2() { wxPrivateOnScopeExit(*this); } void Execute() { (m_obj.*m_memfun)(m_p1, m_p2); } protected: - wxObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) + wxObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) : m_obj(obj), m_memfun(memFun), m_p1(p1), m_p2(p2) { } Obj& m_obj; @@ -272,7 +316,7 @@ protected: const P2 m_p2; }; -template +template inline wxObjScopeGuardImpl2 wxMakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) { @@ -280,42 +324,161 @@ wxMakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) MakeObjGuard(obj, memFun, p1, p2); } +// ---------------------------------------------------------------------------- +// wxVariableSetter: use the same technique as for wxScopeGuard to allow +// setting a variable to some value on block exit +// ---------------------------------------------------------------------------- + +#ifdef wxHAS_NAMESPACES + +namespace wxPrivate +{ + +// empty class just to be able to define a reference to it +class VariableSetterBase { }; + +typedef const VariableSetterBase& VariableSetter; + +template +class VariableSetterImpl : public VariableSetterBase +{ +public: + VariableSetterImpl(T& var, const U& value) + : m_var(var), + m_value(value) + { + } + + ~VariableSetterImpl() + { + m_var = m_value; + } + +private: + T& m_var; + const U& m_value; + + // suppress the warning about assignment operator not being generated + VariableSetterImpl& operator=(const VariableSetterImpl&); +}; + +template +class VariableNullerImpl : public VariableSetterBase +{ +public: + VariableNullerImpl(T& var) + : m_var(var) + { + } + + ~VariableNullerImpl() + { + m_var = NULL; + } + +private: + T& m_var; + + VariableNullerImpl& operator=(const VariableNullerImpl&); +}; + +} // namespace wxPrivate + +template +inline +wxPrivate::VariableSetterImpl wxMakeVarSetter(T& var, const U& value) +{ + return wxPrivate::VariableSetterImpl(var, value); +} + +// calling wxMakeVarSetter(ptr, NULL) doesn't work because U is deduced to be +// "int" and subsequent assignment of "U" to "T *" fails, so provide a special +// function for this special case +template +inline +wxPrivate::VariableNullerImpl wxMakeVarNuller(T& var) +{ + return wxPrivate::VariableNullerImpl(var); +} + +#endif // wxHAS_NAMESPACES + // ============================================================================ -// public stuff +// macros for declaring unnamed scoped guards (which can't be dismissed) // ============================================================================ -// wxScopeGuard is just a reference, see the explanation in CUJ article -typedef const wxScopeGuardImplBase& wxScopeGuard; - -// when an unnamed scope guard is needed, the macros below may be used -// // NB: the original code has a single (and much nicer) ON_BLOCK_EXIT macro // but this results in compiler warnings about unused variables and I // didn't find a way to work around this other than by having different -// macros with different names +// macros with different names or using a less natural syntax for passing +// the arguments (e.g. as Boost preprocessor sequences, which would mean +// having to write wxON_BLOCK_EXIT(fwrite, (buf)(size)(n)(fp)) instead of +// wxON_BLOCK_EXIT4(fwrite, buf, size, n, fp)). + +#define wxGuardName wxMAKE_UNIQUE_NAME(wxScopeGuard) + +#define wxON_BLOCK_EXIT0_IMPL(n, f) \ + wxScopeGuard n = wxMakeGuard(f); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT0(f) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT0_IMPL(wxGuardName, f) +#define wxON_BLOCK_EXIT_OBJ0_IMPL(n, o, m) \ + wxScopeGuard n = wxMakeObjGuard(o, m); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT_OBJ0(o, m) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT_OBJ0_IMPL(wxGuardName, o, &m) + +#define wxON_BLOCK_EXIT_THIS0(m) \ + wxON_BLOCK_EXIT_OBJ0(*this, m) + +#define wxON_BLOCK_EXIT1_IMPL(n, f, p1) \ + wxScopeGuard n = wxMakeGuard(f, p1); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT1(f, p1) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f, p1); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT1_IMPL(wxGuardName, f, p1) +#define wxON_BLOCK_EXIT_OBJ1_IMPL(n, o, m, p1) \ + wxScopeGuard n = wxMakeObjGuard(o, m, p1); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT_OBJ1(o, m, p1) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m, p1); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT_OBJ1_IMPL(wxGuardName, o, &m, p1) +#define wxON_BLOCK_EXIT_THIS1(m, p1) \ + wxON_BLOCK_EXIT_OBJ1(*this, m, p1) + + +#define wxON_BLOCK_EXIT2_IMPL(n, f, p1, p2) \ + wxScopeGuard n = wxMakeGuard(f, p1, p2); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT2(f, p1, p2) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f, p1, p2); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT2_IMPL(wxGuardName, f, p1, p2) +#define wxON_BLOCK_EXIT_OBJ2_IMPL(n, o, m, p1, p2) \ + wxScopeGuard n = wxMakeObjGuard(o, m, p1, p2); \ + wxPrivateUse(n) #define wxON_BLOCK_EXIT_OBJ2(o, m, p1, p2) \ - wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m, p1, p2); \ - wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + wxON_BLOCK_EXIT_OBJ2_IMPL(wxGuardName, o, &m, p1, p2) -#endif // _WX_SCOPEGUARD_H_ +#define wxON_BLOCK_EXIT_THIS2(m, p1, p2) \ + wxON_BLOCK_EXIT_OBJ2(*this, m, p1, p2) + + +#define wxSetterName wxMAKE_UNIQUE_NAME(wxVarSetter) +#define wxON_BLOCK_EXIT_SET_IMPL(n, var, value) \ + wxPrivate::VariableSetter n = wxMakeVarSetter(var, value); \ + wxPrivateUse(n) + +#define wxON_BLOCK_EXIT_SET(var, value) \ + wxON_BLOCK_EXIT_SET_IMPL(wxSetterName, var, value) + +#define wxON_BLOCK_EXIT_NULL_IMPL(n, var) \ + wxPrivate::VariableSetter n = wxMakeVarNuller(var); \ + wxPrivateUse(n) + +#define wxON_BLOCK_EXIT_NULL(ptr) \ + wxON_BLOCK_EXIT_NULL_IMPL(wxSetterName, ptr) + +#endif // _WX_SCOPEGUARD_H_