]> git.saurik.com Git - wxWidgets.git/commitdiff
added convenient wxON_BLOCK_EXIT_SET() macro
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 27 Mar 2008 16:13:50 +0000 (16:13 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 27 Mar 2008 16:13:50 +0000 (16:13 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52857 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/scopeguard.h
interface/scopeguard.h
tests/scopeguard/scopeguardtest.cpp

index 7fd21dcaa67aa27492577a4bcf5ae66526ea4d1b..fe41bfce2ef66854f87612669b766499e4c925fc 100644 (file)
@@ -226,6 +226,7 @@ All:
   if the wxVariantData::Clone function is implemented.
 - Added wxWeakRef<T>, wxScopedPtr<T>, wxSharedPtr<T> class templates
 - Added wxVector<T> class templates
+- Added wxON_BLOCK_EXIT_SET() and wxON_BLOCK_EXIT_NULL() to wx/scopeguard.h.
 
 All (Unix):
 
index fb756c56bfcfcd1bd4503f1fc908f7f02103a166..45fe82f5bf5d21adcc8a695a5cded0f3eb245f6d 100644 (file)
 
 #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 <typename T, typename U>
+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<T, U>& operator=(const VariableSetterImpl<T, U>&);
+};
+
+template <typename T>
+class VariableNullerImpl : public VariableSetterBase
+{
+public:
+    VariableNullerImpl(T& var)
+        : m_var(var)
+    {
+    }
+
+    ~VariableNullerImpl()
+    {
+        m_var = NULL;
+    }
+
+private:
+    T& m_var;
+
+    VariableNullerImpl<T>& operator=(const VariableNullerImpl<T>&);
+};
+
+} // namespace wxPrivate
+
+template <typename T, typename U>
+inline
+wxPrivate::VariableSetterImpl<T, U> wxMakeVarSetter(T& var, const U& value)
+{
+      return wxPrivate::VariableSetterImpl<T, U>(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 <typename T>
+inline
+wxPrivate::VariableNullerImpl<T> wxMakeVarNuller(T& var)
+{
+    return wxPrivate::VariableNullerImpl<T>(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_
index 84002945cc34d189ec31f8bdb362aab95d59ea93..e8c88a7989e95af1c31467fe034632de83a26742 100644 (file)
@@ -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:
 
 #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)
+
+//@}
+
index 977e316af29c8237a7f85b5432742f123ec9e8ec..24c19fd9812ef73a72efb4259e34b61815b34823 100644 (file)
@@ -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 );
+}