From c66cca2af072daf7abe63f784038cbd9125ca4bd Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 5 Jul 2003 23:56:08 +0000 Subject: [PATCH] added wxScopeGuard; test it in the sample git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@21694 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/scopeguard.h | 325 ++++++++++++++++++++++++++++++++++++ samples/console/console.cpp | 34 +++- 2 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 include/wx/scopeguard.h diff --git a/include/wx/scopeguard.h b/include/wx/scopeguard.h new file mode 100644 index 0000000000..2b794dc43f --- /dev/null +++ b/include/wx/scopeguard.h @@ -0,0 +1,325 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/scopeguard.h +// Purpose: declares wxwxScopeGuard and related macros +// Author: Vadim Zeitlin +// Modified by: +// Created: 03.07.2003 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +/* + Acknowledgements: this header is heavily based on (well, almost the exact + copy of) wxScopeGuard.h by Andrei Alexandrescu and Petru Marginean published + in December 2000 issue of C/C++ Users Journal. + */ + +#ifndef _WX_SCOPEGUARD_H_ +#define _WX_SCOPEGUARD_H_ + +#include "wx/defs.h" + +// ---------------------------------------------------------------------------- +// helpers +// ---------------------------------------------------------------------------- + +namespace wxPrivate +{ + // 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) + { + if ( !guard.WasDismissed() ) + { + // we're called from ScopeGuardImpl dtor and so we must not throw +#if wxUSE_EXCEPTIONS + try +#endif // wxUSE_EXCEPTIONS + { + guard.Execute(); + } +#if wxUSE_EXCEPTIONS + catch ( ... ) + { + } +#endif // wxUSE_EXCEPTIONS + } + } + + // just to avoid the warning about unused variables + template + void Use(const T& WXUNUSED(t)) + { + } +} // namespace wxPrivate + +// ============================================================================ +// wxScopeGuard for functions and functors +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxScopeGuardImplBase: used by wxScopeGuardImpl[0..N] below +// ---------------------------------------------------------------------------- + +class wxScopeGuardImplBase +{ +public: + wxScopeGuardImplBase() : m_wasDismissed(false) { } + + void Dismiss() const { m_wasDismissed = true; } + + // 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; + +private: + wxScopeGuardImplBase& operator=(const wxScopeGuardImplBase&); +}; + +// ---------------------------------------------------------------------------- +// wxScopeGuardImpl0: scope guard for actions without parameters +// ---------------------------------------------------------------------------- + +template +class wxScopeGuardImpl0 : public wxScopeGuardImplBase +{ +public: + static wxScopeGuardImpl0 MakeGuard(F fun) + { + return wxScopeGuardImpl0(fun); + } + + ~wxScopeGuardImpl0() { wxPrivate::OnScopeExit(*this); } + + void Execute() { m_fun(); } + +protected: + wxScopeGuardImpl0(F fun) : m_fun(fun) { } + + F m_fun; + + wxScopeGuardImpl0& operator=(const wxScopeGuardImpl0&); +}; + +template +inline wxScopeGuardImpl0 wxMakeGuard(F fun) +{ + return wxScopeGuardImpl0::MakeGuard(fun); +} + +// ---------------------------------------------------------------------------- +// wxScopeGuardImpl1: scope guard for actions with 1 parameter +// ---------------------------------------------------------------------------- + +template +class wxScopeGuardImpl1 : public wxScopeGuardImplBase +{ +public: + static wxScopeGuardImpl1 MakeGuard(F fun, P1 p1) + { + return wxScopeGuardImpl1(fun, p1); + } + + ~wxScopeGuardImpl1() { wxPrivate::OnScopeExit(*this); } + + void Execute() { m_fun(m_p1); } + +protected: + wxScopeGuardImpl1(F fun, P1 p1) : m_fun(fun), m_p1(p1) { } + + F m_fun; + const P1 m_p1; + + wxScopeGuardImpl1& operator=(const wxScopeGuardImpl1&); +}; + +template +inline wxScopeGuardImpl1 wxMakeGuard(F fun, P1 p1) +{ + return wxScopeGuardImpl1::MakeGuard(fun, p1); +} + +// ---------------------------------------------------------------------------- +// wxScopeGuardImpl2: scope guard for actions with 2 parameters +// ---------------------------------------------------------------------------- + +template +class wxScopeGuardImpl2 : public wxScopeGuardImplBase +{ +public: + static wxScopeGuardImpl2 MakeGuard(F fun, P1 p1, P2 p2) + { + return wxScopeGuardImpl2(fun, p1, p2); + } + + ~wxScopeGuardImpl2() { wxPrivate::OnScopeExit(*this); } + + void Execute() { m_fun(m_p1, m_p2); } + +protected: + wxScopeGuardImpl2(F fun, P1 p1, P2 p2) : m_fun(fun), m_p1(p1), m_p2(p2) { } + + F m_fun; + const P1 m_p1; + const P2 m_p2; + + wxScopeGuardImpl2& operator=(const wxScopeGuardImpl2&); +}; + +template +inline wxScopeGuardImpl2 wxMakeGuard(F fun, P1 p1, P2 p2) +{ + return wxScopeGuardImpl2::MakeGuard(fun, p1, p2); +} + +// ============================================================================ +// wxScopeGuards for object methods +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxObjScopeGuardImpl0 +// ---------------------------------------------------------------------------- + +template +class wxObjScopeGuardImpl0 : public wxScopeGuardImplBase +{ +public: + static wxObjScopeGuardImpl0 + MakeObjGuard(Obj& obj, MemFun memFun) + { + return wxObjScopeGuardImpl0(obj, memFun); + } + + ~wxObjScopeGuardImpl0() { wxPrivate::OnScopeExit(*this); } + + void Execute() { (m_obj.*m_memfun)(); } + +protected: + wxObjScopeGuardImpl0(Obj& obj, MemFun memFun) + : m_obj(obj), m_memfun(memFun) { } + + Obj& m_obj; + MemFun m_memfun; +}; + +template +inline wxObjScopeGuardImpl0 wxMakeObjGuard(Obj& obj, MemFun memFun) +{ + return wxObjScopeGuardImpl0::MakeObjGuard(obj, memFun); +} + +template +class wxObjScopeGuardImpl1 : public wxScopeGuardImplBase +{ +public: + static wxObjScopeGuardImpl1 + MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) + { + return wxObjScopeGuardImpl1(obj, memFun, p1); + } + + ~wxObjScopeGuardImpl1() { wxPrivate::OnScopeExit(*this); } + + void Execute() { (m_obj.*m_memfun)(m_p1); } + +protected: + wxObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) + : m_obj(obj), m_memfun(memFun), m_p1(p1) { } + + Obj& m_obj; + MemFun m_memfun; + const P1 m_p1; +}; + +template +inline wxObjScopeGuardImpl1 +wxMakeObjGuard(Obj& obj, MemFun memFun, P1 p1) +{ + return wxObjScopeGuardImpl1::MakeObjGuard(obj, memFun, p1); +} + +template +class wxObjScopeGuardImpl2 : public wxScopeGuardImplBase +{ +public: + static wxObjScopeGuardImpl2 + MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) + { + return wxObjScopeGuardImpl2(obj, memFun, p1, p2); + } + + ~wxObjScopeGuardImpl2() { wxPrivate::OnScopeExit(*this); } + + void Execute() { (m_obj.*m_memfun)(m_p1, m_p2); } + +protected: + wxObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) + : m_obj(obj), m_memfun(memFun), m_p1(p1), m_p2(p2) { } + + Obj& m_obj; + MemFun m_memfun; + const P1 m_p1; + const P2 m_p2; +}; + +template +inline wxObjScopeGuardImpl2 +wxMakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) +{ + return wxObjScopeGuardImpl2:: + MakeObjGuard(obj, memFun, p1, p2); +} + +// ============================================================================ +// public stuff +// ============================================================================ + +// 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 +#define ON_BLOCK_EXIT0(f) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#define ON_BLOCK_EXIT_OBJ0(o, m) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#define ON_BLOCK_EXIT1(f, p1) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f, p1); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#define ON_BLOCK_EXIT_OBJ1(o, m, p1) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m, p1); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#define ON_BLOCK_EXIT2(f, p1, p2) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeGuard(f, p1, p2); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#define ON_BLOCK_EXIT_OBJ2(o, m, p1, p2) \ + wxScopeGuard wxMAKE_UNIQUE_NAME(scopeGuard) = wxMakeObjGuard(o, m, p1, p2); \ + wxPrivate::Use(wxMAKE_UNIQUE_NAME(scopeGuard)) + +#endif // _WX_SCOPEGUARD_H_ + diff --git a/samples/console/console.cpp b/samples/console/console.cpp index 8f932dcdd7..7fbf76d464 100644 --- a/samples/console/console.cpp +++ b/samples/console/console.cpp @@ -95,7 +95,7 @@ #undef TEST_ALL static const bool TEST_ALL = true; #else - #define TEST_FILECONF + #define TEST_LOG static const bool TEST_ALL = false; #endif @@ -2985,6 +2985,38 @@ static void TestRegistryAssociation() #endif // TEST_REGISTRY +// ---------------------------------------------------------------------------- +// scope guard +// ---------------------------------------------------------------------------- + +#include "wx/scopeguard.h" + +static void function0() { puts("function0()"); } +static void function1(int n) { printf("function1(%d)\n", n); } +static void function2(double x, char c) { printf("function2(%g, %c)\n", x, c); } + +struct Object +{ + void method0() { printf("method0()\n"); } + void method1(int n) { printf("method1(%d)\n", n); } + void method2(double x, char c) { printf("method2(%g, %c)\n", x, c); } +}; + +static void TestScopeGuard() +{ + ON_BLOCK_EXIT0(function0); + ON_BLOCK_EXIT1(function1, 17); + ON_BLOCK_EXIT2(function2, 3.14, 'p'); + + Object obj; + ON_BLOCK_EXIT_OBJ0(obj, Object::method0); + ON_BLOCK_EXIT_OBJ1(obj, Object::method1, 7); + ON_BLOCK_EXIT_OBJ2(obj, Object::method2, 2.71, 'e'); + + wxScopeGuard dismissed = wxMakeGuard(function0); + dismissed.Dismiss(); +} + // ---------------------------------------------------------------------------- // sockets // ---------------------------------------------------------------------------- -- 2.45.2