From: Vadim Zeitlin Date: Thu, 27 Mar 2008 16:13:50 +0000 (+0000) Subject: added convenient wxON_BLOCK_EXIT_SET() macro X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/d2a48d5cbc5b3764c6b578238ec6cc5f16c5dd0f added convenient wxON_BLOCK_EXIT_SET() macro git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52857 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index 7fd21dcaa6..fe41bfce2e 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -226,6 +226,7 @@ All: if the wxVariantData::Clone function is implemented. - Added wxWeakRef, wxScopedPtr, wxSharedPtr class templates - Added wxVector class templates +- Added wxON_BLOCK_EXIT_SET() and wxON_BLOCK_EXIT_NULL() to wx/scopeguard.h. All (Unix): diff --git a/include/wx/scopeguard.h b/include/wx/scopeguard.h index fb756c56bf..45fe82f5bf 100644 --- a/include/wx/scopeguard.h +++ b/include/wx/scopeguard.h @@ -51,9 +51,12 @@ #else -#if !defined(__GNUC__) || wxCHECK_GCC_VERSION(2, 95) // 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 @@ -124,6 +127,9 @@ 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 // ---------------------------------------------------------------------------- @@ -318,21 +324,98 @@ 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(scopeGuard) +#define wxGuardName wxMAKE_UNIQUE_NAME(wxScopeGuard) #define wxON_BLOCK_EXIT0_IMPL(n, f) \ wxScopeGuard n = wxMakeGuard(f); \ @@ -381,4 +464,21 @@ typedef const wxScopeGuardImplBase& wxScopeGuard; #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_ diff --git a/interface/scopeguard.h b/interface/scopeguard.h index 84002945cc..e8c88a7989 100644 --- a/interface/scopeguard.h +++ b/interface/scopeguard.h @@ -10,7 +10,7 @@ //@{ /** This macro ensures that the global @a function with 0, 1, 2 or more - parameters (up to some implementaton-defined limit) is executed on scope + parameters (up to some implementation-defined limit) is executed on scope exit, whether due to a normal function return or because an exception has been thrown. A typical example of its usage: @@ -57,3 +57,39 @@ #define wxON_BLOCK_EXIT_THIS2(method, p1, p2) //@} +/** @ingroup group_funcmacro_misc */ +//@{ +/** + This macro sets a variable to the specified value on scope exit. + + Example of usage: + @code + void foo() + { + bool isDoingSomething = true; + { + wxON_BLOCK_EXIT_SET(isDoingSomething, false); + ... do something ... + } + ... isDoingSomething is false now ... + } + @endcode + + @see wxON_BLOCK_EXIT_OBJ0(), wxON_BLOCK_EXIT_NULL() + + @header{wx/scopeguard.h} +*/ +#define wxON_BLOCK_EXIT_SET(var, value) + +/** + This macro sets the pointer passed to it as argument to NULL on scope exit. + + It must be used instead of wxON_BLOCK_EXIT_SET() when the value being set + is @c NULL. + + @header{wx/scopeguard.h} + */ +#define wxON_BLOCK_EXIT_NULL(ptr) + +//@} + diff --git a/tests/scopeguard/scopeguardtest.cpp b/tests/scopeguard/scopeguardtest.cpp index 977e316af2..24c19fd981 100644 --- a/tests/scopeguard/scopeguardtest.cpp +++ b/tests/scopeguard/scopeguardtest.cpp @@ -61,6 +61,7 @@ public: CPPUNIT_TEST(BlockExit); CPPUNIT_TEST(BlockExitObj); CPPUNIT_TEST(BlockExitThis); + CPPUNIT_TEST(BlockExitSetVar); CPPUNIT_TEST_SUITE_END(); void Normal(); @@ -68,6 +69,7 @@ public: void BlockExit(); void BlockExitObj(); void BlockExitThis(); + void BlockExitSetVar(); private: void Zero() { m_count = 0; } @@ -206,3 +208,39 @@ void ScopeGuardTestCase::BlockExitThis() CPPUNIT_ASSERT_EQUAL( 5, m_count ); } +void ScopeGuardTestCase::BlockExitSetVar() +{ + m_count = 1; + { + wxON_BLOCK_EXIT_SET(m_count, 17); + + CPPUNIT_ASSERT_EQUAL( 1, m_count ); + } + CPPUNIT_ASSERT_EQUAL( 17, m_count ); + + + int count = 1; + { + wxON_BLOCK_EXIT_SET(count, 17); + + CPPUNIT_ASSERT_EQUAL( 1, count ); + } + CPPUNIT_ASSERT_EQUAL( 17, count ); + + + wxString s("hi"); + { + wxON_BLOCK_EXIT_SET(s, "bye"); + + WX_ASSERT_STR_EQUAL( "hi", s ); + } + WX_ASSERT_STR_EQUAL( "bye", s ); + + ScopeGuardTestCase *p = this; + { + wxON_BLOCK_EXIT_NULL(p); + + CPPUNIT_ASSERT( p ); + } + CPPUNIT_ASSERT( !p ); +}