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();
};