A smart reference pointer, aka boost::intrusive_ptr.
Relies on the held object to implement ref() and unref() correctly. Serializable using boost.serialization.
#define TEST_RUNTIME 300 // seconds
#include <test.h>
#include <lunchbox/clock.h>
#include <lunchbox/refPtr.h>
#include <lunchbox/referenced.h>
#include <lunchbox/thread.h>
#include <iostream>
#include <boost/intrusive_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#define NTHREADS 24
#define NREFS 200000
{
public:
Foo() {}
private:
virtual ~Foo() {}
friend class boost::serialization::access;
template< class Archive > void serialize( Archive&, unsigned int ) {}
};
FooPtr foo;
{
public:
virtual void run()
{
FooPtr myFoo;
for( size_t i = 0; i<NREFS; ++i )
{
myFoo = foo;
foo = myFoo;
myFoo = 0;
}
}
};
typedef boost::intrusive_ptr<Foo> BoostPtr;
BoostPtr bFoo;
{
public:
virtual void run()
{
BoostPtr myBoost;
for( size_t i = 0; i<NREFS; ++i )
{
myBoost = bFoo;
bFoo = myBoost;
myBoost = 0;
}
}
};
{
public:
Bar() {}
virtual ~Bar() {}
};
typedef boost::shared_ptr<Bar> BarPtr;
BarPtr bBar;
{
public:
virtual void run()
{
BarPtr myBar;
for( size_t i = 0; i<NREFS; ++i )
{
myBar = bBar;
bBar = myBar;
myBar.reset();
}
}
};
int main( int, char** )
{
foo = new Foo;
TestThread threads[NTHREADS];
for( size_t i=0; i<NTHREADS; ++i )
TEST( threads[i].start( ));
for( size_t i=0; i<NTHREADS; ++i )
TEST( threads[i].join( ));
std::cout << time << " ms for " << 3*NREFS << " lunchbox::RefPtr operations"
<< " in " << NTHREADS << " threads ("
<< time/(3*NREFS*NTHREADS)*1000000 << "ns/op)" << std::endl;
TEST( foo->getRefCount() == 1 );
bFoo = new Foo;
BThread bThreads[NTHREADS];
for( size_t i=0; i<NTHREADS; ++i )
TEST( bThreads[i].start( ));
for( size_t i=0; i<NTHREADS; ++i )
TEST( bThreads[i].join( ));
std::cout << bTime << " ms for " << 3*NREFS << " boost::intrusive_ptr ops "
<< "in " << NTHREADS << " threads ("
<< bTime/(3*NREFS*NTHREADS)*1000000 << "ns/op)" << std::endl;
TEST( bFoo->getRefCount() == 1 );
boost::intrusive_ptr< Foo > boostFoo( foo.get( ));
TEST( foo->getRefCount() == 2 );
boostFoo = 0;
TEST( foo->getRefCount() == 1 );
bBar = BarPtr( new Bar );
BarThread barThreads[NTHREADS];
for( size_t i=0; i<NTHREADS; ++i )
TEST( barThreads[i].start( ));
for( size_t i=0; i<NTHREADS; ++i )
TEST( barThreads[i].join( ));
std::cout << barTime << " ms for " << 3*NREFS <<" boost::shared_ptr ops in "
<< NTHREADS << " threads (" << barTime/(3*NREFS*NTHREADS)*1000000
<< "ns/op)" << std::endl;
bBar = boost::make_shared< Bar >();
for( size_t i=0; i<NTHREADS; ++i )
TEST( barThreads[i].start( ));
for( size_t i=0; i<NTHREADS; ++i )
TEST( barThreads[i].join( ));
const float barTime2 = clock.
getTimef();
std::cout << barTime2 << " ms for " << 3*NREFS<<" boost::shared_ptr ops in "
<< NTHREADS << " threads (" << barTime2/(3*NREFS*NTHREADS)*1000000
<< "ns/op) using make_shared" << std::endl;
foo = 0;
FooPtr inFoo1( new Foo );
TEST( inFoo1->getRefCount() == 1 );
FooPtr inFoo2 = inFoo1;
TEST( inFoo2->getRefCount() == 2 );
FooPtr outFoo1;
std::stringstream stream;
boost::archive::text_oarchive oar( stream );
oar & inFoo1;
boost::archive::text_iarchive iar( stream );
iar & outFoo1;
TEST( outFoo1->getRefCount() == 1 );
FooPtr outFoo2 = outFoo1;
TEST( outFoo2->getRefCount() == 2 );
return EXIT_SUCCESS;
}