You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2009/02/03 22:01:04 UTC

svn commit: r740441 - in /activemq/activemq-cpp/trunk/src: main/decaf/lang/Pointer.h test/decaf/lang/PointerTest.cpp test/decaf/lang/PointerTest.h

Author: tabish
Date: Tue Feb  3 21:01:04 2009
New Revision: 740441

URL: http://svn.apache.org/viewvc?rev=740441&view=rev
Log:
https://issues.apache.org/activemq/browse/AMQCPP-100

Add a smart pointer implementation to allow for sharing of command objects without over copying them due to lifetime constraints on command elements.

Modified:
    activemq/activemq-cpp/trunk/src/main/decaf/lang/Pointer.h
    activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.cpp
    activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.h

Modified: activemq/activemq-cpp/trunk/src/main/decaf/lang/Pointer.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/main/decaf/lang/Pointer.h?rev=740441&r1=740440&r2=740441&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/main/decaf/lang/Pointer.h (original)
+++ activemq/activemq-cpp/trunk/src/main/decaf/lang/Pointer.h Tue Feb  3 21:01:04 2009
@@ -26,16 +26,133 @@
 namespace decaf {
 namespace lang {
 
+    template <typename T>
+    class AtomicRefCounter {
+    private:
+
+        decaf::util::concurrent::atomic::AtomicInteger* counter;
+
+    private:
+
+        AtomicRefCounter& operator= ( const AtomicRefCounter& );
+
+    public:
+
+        AtomicRefCounter() :
+            counter( new decaf::util::concurrent::atomic::AtomicInteger( 1 ) ) {}
+        AtomicRefCounter( T* value ) :
+            counter( new decaf::util::concurrent::atomic::AtomicInteger( 1 ) ) {}
+        AtomicRefCounter( const AtomicRefCounter& other ) : counter( other.counter ) {
+            this->counter->incrementAndGet();
+        }
+
+        template< typename U >
+        AtomicRefCounter( const AtomicRefCounter<U>& other ) {
+            this->counter = reinterpret_cast<const AtomicRefCounter<T>& >( other ).counter;
+            this->counter->incrementAndGet();
+        }
+
+        /**
+         * Swaps this instance's reference counter with the one given, this allows
+         * for copy-and-swap semantics of this object.
+         *
+         * @param the value to swap with this one's
+         */
+        void swap( AtomicRefCounter<T>& other ) {
+            std::swap( this->counter, other.counter );
+        }
+
+        /**
+         * Removes a reference to the counter Atomically and returns if the counter
+         * has reached zero, once the counter hits zero, the internal counter is
+         * destroyed and this instance is now considered to be unreferenced.
+         *
+         * @return true if the count is now zero.
+         */
+        bool release() {
+            if( this->counter->decrementAndGet() == 0 ) {
+                delete this->counter;
+                return true;
+            }
+            return false;
+        }
+    };
+
+    template <typename T>
+    class InvasiveCounter {
+    private:
+
+        T* counter;
+
+    private:
+
+        InvasiveCounter& operator= ( const InvasiveCounter& );
+
+    public:
+
+        InvasiveCounter() : counter( NULL ) {}
+
+        InvasiveCounter( T* value ) : counter( value ) {
+
+            if( value != NULL ) {
+                value->addReference();
+            }
+        }
+
+        InvasiveCounter( const InvasiveCounter& other ) : counter( other.counter ) {
+            this->counter->addReference();
+        }
+
+        template< typename U >
+        InvasiveCounter( const InvasiveCounter<U>& other ) {
+            this->counter = reinterpret_cast< const InvasiveCounter<T>& >( other ).counter;
+            this->counter->addReference();
+        }
+
+        /**
+         * Swaps this instance's reference counter with the one given, this allows
+         * for copy-and-swap semantics of this object.
+         *
+         * @param the value to swap with this one's
+         */
+        void swap( InvasiveCounter<T>& other ) {
+            std::swap( this->counter, other.counter );
+        }
+
+        /**
+         * Removes a reference to the counter and returns if the counter
+         * has reached zero.
+         *
+         * @return true if the count is now zero.
+         */
+        bool release() {
+            if( this->counter != NULL ) {
+                return this->counter->releaseReference();
+            }
+
+            return false;
+        }
+    };
+
     /**
      * Decaf's implementation of a Smart Pointer that is a template on a Type
-     * and is Thread Safe.
+     * and is Thread Safe if the default Reference Counter is used.  This Pointer
+     * type allows for the substitution of different Reference Counter implementations
+     * which provide a means of using invasive reference counting if desired using
+     * a custom implementation of <code>ReferenceCounter</code>.
+     * <p>
+     * The Decaf smart pointer provide comparison operators for comparing Pointer
+     * instances in the same manner as normal pointer, except that it does not provide
+     * an overload of operators ( <, <=, >, >= ).  To allow use of a Pointer in a STL
+     * container that requires it, Pointer provides an implementation of std::less.
+     *
+     * @since 1.0
      */
-    template< typename T >
-    class DECAF_API Pointer {
+    template< typename T, typename REFCOUNTER = AtomicRefCounter<T> >
+    class DECAF_API Pointer : public REFCOUNTER {
     private:
 
         T* value;
-        decaf::util::concurrent::atomic::AtomicInteger* refCount;
 
     public:
 
@@ -51,7 +168,7 @@
          * Initialized the contained pointer to NULL, using the -> operator
          * results in an exception unless reset to contain a real value.
          */
-        Pointer() : value( NULL ), refCount( new decaf::util::concurrent::atomic::AtomicInteger( 1 ) ) {}
+        Pointer() : REFCOUNTER(), value( NULL ) {}
 
         /**
          * Explicit Constructor, creates a Pointer that contains value with a
@@ -59,22 +176,25 @@
          *
          * @param value - instance of the type we are containing here.
          */
-        explicit Pointer( const StoredType& value ) :
-            value( value ), refCount( new decaf::util::concurrent::atomic::AtomicInteger( 1 ) ) {
+        explicit Pointer( const StoredType& value ) : REFCOUNTER( value ), value( value ) {
         }
 
         /**
          * Copy constructor. Copies the value contained in the pointer to the new
          * instance and increments the reference counter.
          */
-        Pointer( const Pointer<T>& value ) throw() : value( value.value ), refCount( value.refCount ) {
-            this->refCount->incrementAndGet();
-        }
+        Pointer( const Pointer& value ) throw() : REFCOUNTER( value ), value( value.value ) {}
+
+        /**
+         * Copy constructor. Copies the value contained in the pointer to the new
+         * instance and increments the reference counter.
+         */
+        template< typename T1, typename R1 >
+        Pointer( const Pointer<T1, R1>& value ) throw() : REFCOUNTER( value ), value( value.get() ) {}
 
         virtual ~Pointer() throw() {
-            if( this->refCount->decrementAndGet() == 0 ) {
+            if( this->release() == true ) {
                 delete this->value;
-                delete this->refCount;
             }
         }
 
@@ -106,16 +226,26 @@
          * Exception Safe Swap Function
          * @param value - the value to swap with this.
          */
-        void swap( Pointer<T>& value ) throw() {
+        void swap( Pointer& value ) throw() {
             std::swap( this->value, value.value );
-            std::swap( this->refCount, value.refCount );
+            REFCOUNTER::swap( value );
         }
 
         /**
          * Assigns the value of right to this Pointer and increments the reference Count.
          * @param right - Pointer on the right hand side of an operator= call to this.
          */
-        Pointer& operator= ( const Pointer<T>& right ) throw() {
+        Pointer& operator= ( const Pointer& right ) throw() {
+            if( this == &right ) {
+                return *this;
+            }
+
+            Pointer temp( right );
+            temp.swap( *this );
+            return *this;
+        }
+        template< typename T1, typename R1>
+        Pointer& operator= ( const Pointer<T1, R1>& right ) throw() {
             if( this == &right ) {
                 return *this;
             }
@@ -191,18 +321,42 @@
             return left != right.get();
         }
 
-        template< typename U >
-        bool operator==( const Pointer<U>& right ) const {
+        template< typename T1, typename R1 >
+        bool operator==( const Pointer<T1, R1>& right ) const {
             return this->value == right.get();
         }
 
-        template< typename U >
-        bool operator!=( const Pointer<U>& right ) const {
+        template< typename T1, typename R1 >
+        bool operator!=( const Pointer<T1, R1>& right ) const {
             return !( this->value == right.get() );
         }
 
     };
 
+    ////////////////////////////////////////////////////////////////////////////
+    template< typename T, typename R, typename U >
+    inline bool operator==( const Pointer<T, R>& left, const U* right ) {
+        return left.get() == right;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    template< typename T, typename R, typename U >
+    inline bool operator==( const U* left, const Pointer<T, R>& right ) {
+        return right.get() == left;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    template< typename T, typename R, typename U >
+    inline bool operator!=( const Pointer<T, R>& left, const U* right ) {
+        return !( left.get() == right );
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    template< typename T, typename R, typename U >
+    inline bool operator!=( const U* left, const Pointer<T, R>& right ) {
+        return right.get() != left;
+    }
+
 }}
 
 ////////////////////////////////////////////////////////////////////////////////

Modified: activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.cpp?rev=740441&r1=740440&r2=740441&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.cpp (original)
+++ activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.cpp Tue Feb  3 21:01:04 2009
@@ -18,6 +18,8 @@
 #include "PointerTest.h"
 
 #include <decaf/lang/Pointer.h>
+#include <decaf/lang/Thread.h>
+#include <decaf/lang/Runnable.h>
 
 #include <map>
 #include <string>
@@ -71,6 +73,11 @@
 };
 
 ////////////////////////////////////////////////////////////////////////////////
+struct X {
+    Pointer<X> next;
+};
+
+////////////////////////////////////////////////////////////////////////////////
 void PointerTest::testBasics() {
 
     TestClassA* thePointer = new TestClassA();
@@ -96,6 +103,11 @@
 
     copy.reset( NULL );
     CPPUNIT_ASSERT( copy.get() == NULL );
+
+    Pointer<X> p( new X );
+    p->next = Pointer<X>( new X );
+    p = p->next;
+    CPPUNIT_ASSERT( !p->next );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -205,10 +217,52 @@
     CPPUNIT_ASSERT( pointer1 != NULL );
     CPPUNIT_ASSERT( !pointer1 == false );
     CPPUNIT_ASSERT( !!pointer1 == true );
+
+    // This won't compile which is correct.
+    //Pointer<TestClassB> pointer5( new TestClassB );
+    //Pointer<TestClassA> pointer6( new TestClassA );
+    //CPPUNIT_ASSERT( pointer5 != pointer6 );
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+class PointerTestRunnable : public decaf::lang::Runnable {
+private:
+
+    Pointer<TestClassA> mine;
+
+public:
+
+    PointerTestRunnable( const Pointer<TestClassA>& value ) : mine( value ) {}
+
+    void run() {
+
+        for( int i = 0; i < 999; ++i ) {
+            Pointer<TestClassBase> copy = this->mine;
+            CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
+            copy.reset( new TestClassB() );
+            CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
+        }
+    }
+};
+
+////////////////////////////////////////////////////////////////////////////////
 void PointerTest::testThreaded1() {
+    Pointer<TestClassA> pointer( new TestClassA() );
+
+    PointerTestRunnable runnable( pointer );
+    Thread testThread( &runnable );
+
+    testThread.start();
+
+    for( int i = 0; i < 999; ++i ) {
+        Pointer<TestClassBase> copy = pointer;
+        CPPUNIT_ASSERT( copy->returnHello() == "Hello" );
+        Thread::yield();
+        copy.reset( new TestClassB() );
+        CPPUNIT_ASSERT( copy->returnHello() == "GoodBye" );
+    }
+
+    testThread.join();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -264,8 +318,58 @@
     testMap.insert( std::make_pair( pointer1, "Bob" ) );
     testMap.insert( std::make_pair( pointer2, "Steve" ) );
     testMap.insert( std::make_pair( pointer3, "Steve" ) );
+
+    // Two and Three should be equivalent (not equal) but in this case
+    // equivalent is what matters.  So pointer2 should be bumped out of the map.
+    CPPUNIT_ASSERT( testMap.size() == 2 );
+
     testMap.insert( std::make_pair( Pointer<TestClassBase>( new TestClassA ), "Fred" ) );
 
     CPPUNIT_ASSERT( testMap.find( pointer1 ) != testMap.end() );
     CPPUNIT_ASSERT( testMap.find( pointer2 ) != testMap.end() );
 }
+
+////////////////////////////////////////////////////////////////////////////////
+class SelfCounting {
+private:
+
+    int refCount;
+
+public:
+
+    SelfCounting() : refCount( 0 ) {}
+    SelfCounting( const SelfCounting& other ) : refCount( other.refCount ) {}
+
+    void addReference() { this->refCount++; }
+    bool releaseReference() { return !( --this->refCount ); }
+
+    std::string returnHello() { return "Hello"; }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+void PointerTest::testInvasive() {
+
+    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > thePointer( new SelfCounting );
+
+    // Test Null Initialize
+    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > nullPointer;
+    CPPUNIT_ASSERT( nullPointer.get() == NULL );
+
+    // Test Value Constructor
+    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > pointer( thePointer );
+    CPPUNIT_ASSERT( pointer.get() == thePointer );
+
+    // Test Copy Constructor
+    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > ctorCopy( pointer );
+    CPPUNIT_ASSERT( ctorCopy.get() == thePointer );
+
+    // Test Assignment
+    Pointer< SelfCounting, InvasiveCounter<SelfCounting> > copy = pointer;
+    CPPUNIT_ASSERT( copy.get() == thePointer );
+
+    CPPUNIT_ASSERT( ( *pointer ).returnHello() == "Hello" );
+    CPPUNIT_ASSERT( pointer->returnHello() == "Hello" );
+
+    copy.reset( NULL );
+    CPPUNIT_ASSERT( copy.get() == NULL );
+}

Modified: activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.h?rev=740441&r1=740440&r2=740441&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.h (original)
+++ activemq/activemq-cpp/trunk/src/test/decaf/lang/PointerTest.h Tue Feb  3 21:01:04 2009
@@ -34,6 +34,7 @@
         CPPUNIT_TEST( testThreaded2 );
         CPPUNIT_TEST( testOperators );
         CPPUNIT_TEST( testSTLContainers );
+        CPPUNIT_TEST( testInvasive );
         CPPUNIT_TEST_SUITE_END();
 
     public:
@@ -48,6 +49,7 @@
         void testThreaded2();
         void testOperators();
         void testSTLContainers();
+        void testInvasive();
 
     };