Added Example.COW_debug.cc. A simple class using an implementation
authorMichael Andres <ma@suse.de>
Tue, 6 Dec 2005 22:39:55 +0000 (22:39 +0000)
committerMichael Andres <ma@suse.de>
Tue, 6 Dec 2005 22:39:55 +0000 (22:39 +0000)
class and performing COW. Additionally using a simple tracer
(debug.h) to trace the implementation class and counting the
instances in memory.

devel/Example.COW_debug.cc [new file with mode: 0644]
devel/Makefile.am
devel/devel.ma/Main.cc
zypp/base/Debug.h

diff --git a/devel/Example.COW_debug.cc b/devel/Example.COW_debug.cc
new file mode 100644 (file)
index 0000000..e7cab49
--- /dev/null
@@ -0,0 +1,230 @@
+#include <iosfwd>
+#include "zypp/base/PtrTypes.h"
+
+///////////////////////////////////////////////////////////////////
+// MyClass.h
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  /** Simple class using a RWCOW_pointer to implementation.
+   *
+   * MyClass maintains an int value, manipulated via get/set.
+   * RWCOW_pointer provides the 'copy on write' functionality.
+  */
+  class MyClass
+  {
+  public:
+    /** Implementation (public, but hidden in MyClass.cc) */
+    struct Impl;
+
+  public:
+    MyClass( int val = 0 );
+
+    int get() const;
+
+    void set( int val );
+
+  private:
+    /** Pointer to implementation */
+    RWCOW_pointer<Impl> _pimpl;
+  };
+  ///////////////////////////////////////////////////////////////////
+}
+///////////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////
+// MyClass.cc
+///////////////////////////////////////////////////////////////////
+#include <zypp/base/Debug.h>
+
+using std::endl;
+
+namespace zypp
+{
+  ///////////////////////////////////////////////////////////////////
+  //
+  namespace debug
+  {
+    /** Forward decl. Implemented after MyClass::Impl is defined,
+     * if you want to dynamic_cast TraceCAD<MyClass::Impl> back into
+     * MyClass::Impl. Otherwise you could implement it here.
+     */
+    template<>
+      void traceCAD( TraceCADBase::What what_r,
+                     const TraceCAD<MyClass::Impl> & self_r,
+                     const TraceCAD<MyClass::Impl> & rhs_r );
+  }
+  //
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  /** Implementation of MyClass providing the int value.
+   *
+   * To debug via TraceCAD, simply derive. Per default TraceCAD
+   * drops loglines. In this example we overload traceCAD<Impl>,
+   * to do a bit more stuff.
+  */
+  struct MyClass::Impl : public debug::TraceCAD<Impl>
+  {
+    Impl( int val = 0 )
+    : _value( val )
+    {}
+
+    int _value;
+
+  private:
+    friend Impl * rwcowClone<Impl>( const Impl * rhs );
+    /** clone for RWCOW_pointer */
+    Impl * clone() const
+    { return new Impl( *this ); }
+  };
+  ///////////////////////////////////////////////////////////////////
+
+  inline std::ostream & operator<<( std::ostream & str, const MyClass::Impl & obj )
+  { return str << "MyClass::Impl[" << &obj << "] value: " << obj._value; }
+
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  // class MyClass
+  ///////////////////////////////////////////////////////////////////
+
+  MyClass::MyClass( int val )
+  : _pimpl( new Impl( val ) )
+  {
+    // e.g _PING to indicate ctor is done.
+    _pimpl->_PING();
+  }
+
+  /** Impl access via 'operator->() const' (readonly) */
+  int MyClass::get() const
+  { return _pimpl->_value; }
+
+  /** Impl access via 'operator->()' (write, creates a copy iff shared) */
+  void MyClass::set( int val )
+  { _pimpl->_value = val; }
+
+  ///////////////////////////////////////////////////////////////////
+  //
+  namespace debug
+  {
+    /** Performs all possible casts of self_r/rhs_r back into
+     * MyClass::Impl.
+     *
+     * CTOR,DTOR: self_r can't be casted, because MyClass::Impl
+     * is not yet constructed (TraceCAD is base class), or already
+     * deleted. rhs_r is meaningless (==self_r).
+     *
+     * COPYCTOR: self_r can't be casted (not yet constructed).
+     * rhs_r can be casted into MyClass::Impl. It's the object
+     * we copy from.
+     *
+     * ASSIGN: self_r and rhs_r can be casted. If MyClass::Impl
+     * defines an operator==, you have to alter the code to call
+     * TraceCAD::operator=. Otherwise it won't be triggered.
+     *
+     * PING: self_r can be casted, rhs_r is meaningless (==self_r).
+     * You have to alter MyClass::Impl to call '_PING()' to recieve
+     * the trigger. The only purpose is to provide an easy way to
+     * trigger some action, without much changes to the original code.
+     * Call _PING there and perfrorm the action here, if possible.
+    */
+    template<>
+      void traceCAD( TraceCADBase::What what_r,
+                     const TraceCAD<MyClass::Impl> & self_r,
+                     const TraceCAD<MyClass::Impl> & rhs_r )
+      {
+        static unsigned instanceCouter = 0;
+        // lazy #define ;)
+#define STATS "\t(total " << instanceCouter << ")"
+
+        switch( what_r )
+          {
+          case TraceCADBase::CTOR:
+            ++instanceCouter;
+            SEC << self_r << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::DTOR:
+            --instanceCouter;
+            SEC << self_r << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::PING:
+            SEC << dynamic_cast<const MyClass::Impl &>(self_r)
+                << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::COPYCTOR:
+            ++instanceCouter;
+            SEC << self_r << what_r << "( "
+                << dynamic_cast<const MyClass::Impl &>(rhs_r)
+                << ")" << STATS << std::endl;
+            break;
+
+          case TraceCADBase::ASSIGN:
+            SEC << dynamic_cast<const MyClass::Impl &>(self_r)
+                << what_r << "( "
+                << dynamic_cast<const MyClass::Impl &>(rhs_r)
+                << ")" << STATS << std::endl;
+            break;
+          }
+      }
+  }
+  //
+  ///////////////////////////////////////////////////////////////////
+}
+///////////////////////////////////////////////////////////////////
+
+/******************************************************************
+**
+**
+**      FUNCTION NAME : main
+**      FUNCTION TYPE : int
+**
+**      DESCRIPTION :
+*/
+int main( int argc, char * argv[] )
+{
+  INT << "===[START]==========================================" << endl;
+  using zypp::MyClass;
+
+  MyClass c; // MyClass::Impl CTOR
+  MyClass d( c ); // shares Impl
+  MyClass e( d ); // shares Impl
+
+  MIL << "c.get" << c.get() << endl;
+  MIL << "d.get" << d.get() << endl;
+  MIL << "e.get" << e.get() << endl;
+
+  DBG << "will d.set( 4 )..." << endl;
+  d.set( 4 ); // performs COW
+  DBG << "done d.set( 4 )" << endl;
+
+  MIL << "c.get" << c.get() << endl;
+  MIL << "d.get" << d.get() << endl;
+  MIL << "e.get" << e.get() << endl;
+
+  DBG << "will e=d..." << endl;
+  e = d; // shares Impl
+  DBG << "done e=d" << endl;
+
+  MIL << "c.get" << c.get() << endl;
+  MIL << "d.get" << d.get() << endl;
+  MIL << "e.get" << e.get() << endl;
+
+  DBG << "will e.set( 1 )..." << endl;
+  e.set( 1 ); // performs COW
+  DBG << "done e.set( c )" << endl;
+
+  MIL << "c.get" << c.get() << endl;
+  MIL << "d.get" << d.get() << endl;
+  MIL << "e.get" << e.get() << endl;
+
+  INT << "===[END]============================================" << endl;
+  return 0;
+  // Tree times MyClass::Impl DTOR
+}
index a092b6f870444e9876a8601a361705e8aff1de09..9b52026fb1ec18390a95bd05c25dd1c26df4fa80 100644 (file)
@@ -10,7 +10,8 @@ SUBDIRS =
 
 noinst_PROGRAMS = \
        Example.createResolvable        \
-       Example.createCapabilities
+       Example.createCapabilities      \
+       Example.COW_debug
 
 ## ##################################################
 
@@ -20,6 +21,7 @@ LDADD =       $(top_srcdir)/zypp/lib@PACKAGE@.la
 
 Example_createResolvable_SOURCES = Example.createResolvable.cc
 Example_createCapabilities_SOURCES = Example.createCapabilities.cc
+Example_COW_debug_SOURCES = Example.COW_debug.cc
 
 ## ##################################################
 
index 3413eba2cef6c3110d61f623228aefeef12330ba..e7cab49699ce1758c92a801708bf6e2e6678a7a7 100644 (file)
@@ -7,11 +7,15 @@
 namespace zypp
 {
   ///////////////////////////////////////////////////////////////////
+  /** Simple class using a RWCOW_pointer to implementation.
+   *
+   * MyClass maintains an int value, manipulated via get/set.
+   * RWCOW_pointer provides the 'copy on write' functionality.
+  */
   class MyClass
-  ///////////////////////////////////////////////////////////////////
   {
   public:
-    /** Implementation */
+    /** Implementation (public, but hidden in MyClass.cc) */
     struct Impl;
 
   public:
@@ -41,8 +45,29 @@ using std::endl;
 namespace zypp
 {
   ///////////////////////////////////////////////////////////////////
-  struct MyClass::Impl : public debug::TraceCAD<Impl>
+  //
+  namespace debug
+  {
+    /** Forward decl. Implemented after MyClass::Impl is defined,
+     * if you want to dynamic_cast TraceCAD<MyClass::Impl> back into
+     * MyClass::Impl. Otherwise you could implement it here.
+     */
+    template<>
+      void traceCAD( TraceCADBase::What what_r,
+                     const TraceCAD<MyClass::Impl> & self_r,
+                     const TraceCAD<MyClass::Impl> & rhs_r );
+  }
+  //
+  ///////////////////////////////////////////////////////////////////
+
   ///////////////////////////////////////////////////////////////////
+  /** Implementation of MyClass providing the int value.
+   *
+   * To debug via TraceCAD, simply derive. Per default TraceCAD
+   * drops loglines. In this example we overload traceCAD<Impl>,
+   * to do a bit more stuff.
+  */
+  struct MyClass::Impl : public debug::TraceCAD<Impl>
   {
     Impl( int val = 0 )
     : _value( val )
@@ -58,20 +83,99 @@ namespace zypp
   };
   ///////////////////////////////////////////////////////////////////
 
+  inline std::ostream & operator<<( std::ostream & str, const MyClass::Impl & obj )
+  { return str << "MyClass::Impl[" << &obj << "] value: " << obj._value; }
+
+  ///////////////////////////////////////////////////////////////////
+
   ///////////////////////////////////////////////////////////////////
   // class MyClass
   ///////////////////////////////////////////////////////////////////
 
   MyClass::MyClass( int val )
   : _pimpl( new Impl( val ) )
-  {}
+  {
+    // e.g _PING to indicate ctor is done.
+    _pimpl->_PING();
+  }
 
+  /** Impl access via 'operator->() const' (readonly) */
   int MyClass::get() const
   { return _pimpl->_value; }
 
+  /** Impl access via 'operator->()' (write, creates a copy iff shared) */
   void MyClass::set( int val )
   { _pimpl->_value = val; }
 
+  ///////////////////////////////////////////////////////////////////
+  //
+  namespace debug
+  {
+    /** Performs all possible casts of self_r/rhs_r back into
+     * MyClass::Impl.
+     *
+     * CTOR,DTOR: self_r can't be casted, because MyClass::Impl
+     * is not yet constructed (TraceCAD is base class), or already
+     * deleted. rhs_r is meaningless (==self_r).
+     *
+     * COPYCTOR: self_r can't be casted (not yet constructed).
+     * rhs_r can be casted into MyClass::Impl. It's the object
+     * we copy from.
+     *
+     * ASSIGN: self_r and rhs_r can be casted. If MyClass::Impl
+     * defines an operator==, you have to alter the code to call
+     * TraceCAD::operator=. Otherwise it won't be triggered.
+     *
+     * PING: self_r can be casted, rhs_r is meaningless (==self_r).
+     * You have to alter MyClass::Impl to call '_PING()' to recieve
+     * the trigger. The only purpose is to provide an easy way to
+     * trigger some action, without much changes to the original code.
+     * Call _PING there and perfrorm the action here, if possible.
+    */
+    template<>
+      void traceCAD( TraceCADBase::What what_r,
+                     const TraceCAD<MyClass::Impl> & self_r,
+                     const TraceCAD<MyClass::Impl> & rhs_r )
+      {
+        static unsigned instanceCouter = 0;
+        // lazy #define ;)
+#define STATS "\t(total " << instanceCouter << ")"
+
+        switch( what_r )
+          {
+          case TraceCADBase::CTOR:
+            ++instanceCouter;
+            SEC << self_r << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::DTOR:
+            --instanceCouter;
+            SEC << self_r << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::PING:
+            SEC << dynamic_cast<const MyClass::Impl &>(self_r)
+                << what_r << STATS << std::endl;
+            break;
+
+          case TraceCADBase::COPYCTOR:
+            ++instanceCouter;
+            SEC << self_r << what_r << "( "
+                << dynamic_cast<const MyClass::Impl &>(rhs_r)
+                << ")" << STATS << std::endl;
+            break;
+
+          case TraceCADBase::ASSIGN:
+            SEC << dynamic_cast<const MyClass::Impl &>(self_r)
+                << what_r << "( "
+                << dynamic_cast<const MyClass::Impl &>(rhs_r)
+                << ")" << STATS << std::endl;
+            break;
+          }
+      }
+  }
+  //
+  ///////////////////////////////////////////////////////////////////
 }
 ///////////////////////////////////////////////////////////////////
 
@@ -88,33 +192,33 @@ int main( int argc, char * argv[] )
   INT << "===[START]==========================================" << endl;
   using zypp::MyClass;
 
-  MyClass c;
-  MyClass d( c );
-  MyClass e( d );
+  MyClass c; // MyClass::Impl CTOR
+  MyClass d( c ); // shares Impl
+  MyClass e( d ); // shares Impl
 
   MIL << "c.get" << c.get() << endl;
   MIL << "d.get" << d.get() << endl;
   MIL << "e.get" << e.get() << endl;
 
   DBG << "will d.set( 4 )..." << endl;
-  d.set( 4 );
+  d.set( 4 ); // performs COW
   DBG << "done d.set( 4 )" << endl;
 
   MIL << "c.get" << c.get() << endl;
   MIL << "d.get" << d.get() << endl;
   MIL << "e.get" << e.get() << endl;
 
-  DBG << "will d.set( 5 )..." << endl;
-  d.set( 5 );
-  DBG << "done d.set( 5 )" << endl;
+  DBG << "will e=d..." << endl;
+  e = d; // shares Impl
+  DBG << "done e=d" << endl;
 
   MIL << "c.get" << c.get() << endl;
   MIL << "d.get" << d.get() << endl;
   MIL << "e.get" << e.get() << endl;
 
-  DBG << "will c.set( 1 )..." << endl;
-  c.set( 5 );
-  DBG << "done c.set( c )" << endl;
+  DBG << "will e.set( 1 )..." << endl;
+  e.set( 1 ); // performs COW
+  DBG << "done e.set( c )" << endl;
 
   MIL << "c.get" << c.get() << endl;
   MIL << "d.get" << d.get() << endl;
@@ -122,41 +226,5 @@ int main( int argc, char * argv[] )
 
   INT << "===[END]============================================" << endl;
   return 0;
+  // Tree times MyClass::Impl DTOR
 }
-
-#if 0
-
-///////////////////////////////////////////////////////////////////
-namespace zypp
-{ /////////////////////////////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////
-  namespace debug
-  { /////////////////////////////////////////////////////////////////
-
-    template<>
-      void watchCAD( WatchCADBase::What what_r,
-                     const WatchCAD<Dependencies::Impl> & self_r,
-                     const WatchCAD<Dependencies::Impl> & rhs_r )
-      {
-        switch( what_r )
-          {
-          case WatchCADBase::CTOR:
-          case WatchCADBase::DTOR:
-            SEC << self_r << what_r << std::endl;
-            break;
-          case WatchCADBase::COPYCTOR:
-          case WatchCADBase::ASSIGN:
-            SEC << self_r << what_r << "( "
-            << dynamic_cast<const Dependencies::Impl &>(rhs_r)
-            << ")" << std::endl;
-            break;
-          }
-      }
-
-    /////////////////////////////////////////////////////////////////
-  } // namespace debug
-  ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // namespace zypp
-///////////////////////////////////////////////////////////////////
-#endif
index cc77261c968c57918c2b6a3ddcd4a8ece73fc66d..6246bf45cf5d6a6e97df3a8ffb45668ca4051328 100644 (file)
@@ -25,17 +25,29 @@ namespace zypp
   namespace debug
   { /////////////////////////////////////////////////////////////////
 
+    /** \defgroup DEBUG Debug tools
+    */
+
 #define TAG INT << __PRETTY_FUNCTION__ << std::endl
 
     ///////////////////////////////////////////////////////////////////
+    /** \defgroup DBG_TRACER Tracer
+     * \ingroup DEBUG
+     */
+    //@{
+    /** Base for a simple tracer. Provides an enum indicating which
+     * traced functions were called.
+    */
     struct TraceCADBase
     {
       enum What { CTOR, COPYCTOR, ASSIGN, DTOR, PING };
     };
 
+    /** \relates TraceCADBase Stream output. */
     inline std::ostream & operator<<( std::ostream & str, const TraceCADBase & obj )
     { return str << "TraceCAD[" << &obj << "] "; }
 
+    /** \relates TraceCADBase Stream output of TraceCADBase::What. */
     inline std::ostream & operator<<( std::ostream & str, TraceCADBase::What obj )
     {
       switch( obj )
@@ -49,6 +61,26 @@ namespace zypp
       return str;
     }
 
+    /** A simple tracer. To trace class Foo, derive public from
+     * TraceCAD<Foo>. This tracer simply calls traceCAD in each
+     * traced method, and traceCAD simply drops a line in the log.
+     *
+     * This tracer logs construction, copy construction, assignment,
+     * destruction and _PING.
+     *
+     * assignment: In case the traced class defines an operator=
+     * it must be altered to call TraceCAD::operator=, otherwise it
+     * won't be triggered.
+     *
+     * _PING: Completely up to you. Call _PING somewhere in the traced
+     * class to indicate something. In case you overload traceCAD, do
+     * whatever is appropriate on _PING. It's just an offer to perform
+     * logging or actions here, and not in the traced code.
+     *
+     * But traceCAD may be overloaded to produce more stats.
+     *
+     * \see \c Example.COW_debug.cc.
+     */
     template<class _Tp>
       struct TraceCAD : public TraceCADBase
       {
@@ -68,6 +100,9 @@ namespace zypp
         { traceCAD( PING, *this, *this ); }
       };
 
+    /** Drop a log line about the traced method. Overload to
+     * fit your needs.
+    */
     template<class _Tp>
       void traceCAD( TraceCADBase::What what_r,
                      const TraceCAD<_Tp> & self_r,
@@ -86,6 +121,8 @@ namespace zypp
             break;
           }
       }
+    //@}
+    ///////////////////////////////////////////////////////////////////
 
     /////////////////////////////////////////////////////////////////
   } // namespace debug