#include "Teuchos_RefCountPtr.hpp"
#include "Teuchos_GlobalMPISession.hpp"
#include "Teuchos_oblackholestream.hpp"
#include "Teuchos_CommandLineProcessor.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
#include "Teuchos_Version.hpp"
#ifdef HAVE_TEUCHOS_BOOST
# include "Teuchos_RefCountPtrBoostSharedPtrConversions.hpp"
#endif
const int
A_g_return = 1,
A_f_return = 2,
B1_g_return = 3,
B1_f_return = 4,
B2_g_return = 5,
B2_f_return = 6,
C_g_return = 7,
C_f_return = 8,
D_g_return = 9,
D_f_return = 10,
E_g_return = 11,
E_f_return = 12;
class C;
class A {
int A_g_, A_f_;
public:
A() : A_g_(A_g_return), A_f_(A_f_return) {}
virtual ~A();
virtual int A_g() { return A_g_; }
virtual int A_f() const { return A_f_; }
#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
private:
Teuchos::RefCountPtr<C> c_;
public:
void set_C(const Teuchos::RefCountPtr<C> &c ) { c_ = c; }
#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
};
class B1 : virtual public A {
int B1_g_, B1_f_;
public:
B1() : B1_g_(B1_g_return), B1_f_(B1_f_return) {}
~B1() { B1_g_ = -1; B1_f_ = -1; }
virtual int B1_g() { return B1_g_; }
virtual int B1_f() const { return B1_f_; }
};
class B2 : virtual public A {
int B2_g_, B2_f_;
public:
B2() : B2_g_(B2_g_return), B2_f_(B2_f_return) {}
~B2() { B2_g_ = -1; B2_f_ = -1; }
virtual int B2_g() { return B2_g_; }
virtual int B2_f() const { return B2_f_; }
};
class C : virtual public B1, virtual public B2
{
int C_g_, C_f_;
public:
C() : C_g_(C_g_return),C_f_(C_f_return) {}
~C() { C_g_ = -1; C_f_ = -1; }
virtual int C_g() { return C_g_; }
virtual int C_f() const { return C_f_; }
#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
private:
Teuchos::RefCountPtr<A> a_;
public:
void set_A(const Teuchos::RefCountPtr<A> &a ) { a_ = a; }
#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
};
A::~A() { A_g_ = -1; A_f_ = -1; }
class Get_A_f_return {
const A *a_;
int *a_f_return_;
Get_A_f_return();
public:
Get_A_f_return( const A *a, int *a_f_return ) : a_(a), a_f_return_(a_f_return) {}
~Get_A_f_return() { *a_f_return_ = a_->A_f(); }
};
void deallocA(A* ptr)
{
std::cout << "\nCalled deallocA(...)!\n";
delete ptr;
}
void deallocHandleA(A** handle)
{
std::cout << "\nCalled deallocHandleA(...)!\n";
A *ptr = *handle;
delete ptr;
*handle = 0;
}
class D
{
int D_g_, D_f_;
public:
D() : D_g_(D_g_return), D_f_(D_f_return) {}
int D_g() { return D_g_; }
int D_f() const { return D_f_; }
};
class E : public D
{
int E_g_, E_f_;
public:
E() : E_g_(E_g_return), E_f_(E_f_return) {}
int E_g() { return E_g_; }
int E_f() const { return E_f_; }
};
#define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
#define SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
int main( int argc, char* argv[] ) {
using Teuchos::RefCountPtr;
using Teuchos::DeallocDelete;
using Teuchos::deallocFunctorDelete;
using Teuchos::deallocFunctorHandleDelete;
using Teuchos::null;
using Teuchos::rcp;
using Teuchos::is_null;
using Teuchos::rcp_implicit_cast;
using Teuchos::rcp_const_cast;
using Teuchos::rcp_static_cast;
using Teuchos::rcp_dynamic_cast;
using Teuchos::set_extra_data;
using Teuchos::get_extra_data;
using Teuchos::get_optional_extra_data;
using Teuchos::get_dealloc;
using Teuchos::get_optional_dealloc;
using Teuchos::CommandLineProcessor;
bool success = true, verbose = true;
Teuchos::GlobalMPISession mpiSession(&argc,&argv);
const int procRank = Teuchos::GlobalMPISession::getRank();
Teuchos::oblackholestream blackhole;
std::ostream &out = ( procRank == 0 ? std::cout : blackhole );
try {
CommandLineProcessor clp(false);
clp.setOption( "verbose", "quiet", &verbose, "Set if output is printed or not." );
CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
out << "\nEnd Result: TEST FAILED" << endl;
return parse_return;
}
blackhole << "\nThis should not print anywhere.\n";
if(verbose)
out << std::endl << Teuchos::Teuchos_Version() << std::endl;
if(verbose)
out << "\nTesting basic RefCountPtr functionality ...\n";
RefCountPtr<A> a_ptr1 = rcp(new C);
if(verbose)
out << "\na_ptr1 = " << a_ptr1 << "\n";
#ifndef __sun
TEST_FOR_EXCEPT( a_ptr1.count() != 1 );
#endif
TEST_FOR_EXCEPT( a_ptr1.get() == NULL );
TEST_FOR_EXCEPT( a_ptr1 == null );
TEST_FOR_EXCEPT( !(a_ptr1 != null) );
TEST_FOR_EXCEPT( is_null(a_ptr1) );
RefCountPtr<D> d_ptr1 = rcp(new E);
#ifndef __sun
TEST_FOR_EXCEPT( d_ptr1.count() != 1 );
#endif
TEST_FOR_EXCEPT( d_ptr1.get() == NULL);
if(1) {
const RefCountPtr<const A> ca_ptr1 = rcp_const_cast<const A>(a_ptr1);
TEST_FOR_EXCEPT( !(ca_ptr1 == a_ptr1) );
TEST_FOR_EXCEPT( ca_ptr1 != a_ptr1 );
#ifndef __sun
TEST_FOR_EXCEPT( a_ptr1.count() != 2 );
#endif
TEST_FOR_EXCEPT( ca_ptr1.get() == NULL );
#ifndef __sun
TEST_FOR_EXCEPT( ca_ptr1.count() != 2 );
#endif
const RefCountPtr<const D> cd_ptr1 = rcp_const_cast<const D>(d_ptr1);
#ifndef __sun
TEST_FOR_EXCEPT( d_ptr1.count() != 2 );
#endif
TEST_FOR_EXCEPT( cd_ptr1.get() == NULL );
#ifndef __sun
TEST_FOR_EXCEPT( cd_ptr1.count() != 2 );
#endif
#ifdef SHOW_RUN_TIME_ERROR_1
const RefCountPtr<A> a_ptr2 = a_ptr1.get();
#endif
a_ptr1 = rcp_const_cast<A>(ca_ptr1.assert_not_null());
#ifdef SHOW_COMPILE_TIME_ERRORS
ca_ptr1 = ca_ptr1;
ca_ptr1->A_g();
#endif
TEST_FOR_EXCEPT( a_ptr1->A_g() != A_g_return );
TEST_FOR_EXCEPT( a_ptr1->A_f() != A_f_return );
TEST_FOR_EXCEPT( ca_ptr1->A_f() != A_f_return );
TEST_FOR_EXCEPT( d_ptr1->D_g() != D_g_return );
TEST_FOR_EXCEPT( d_ptr1->D_f() != D_f_return );
TEST_FOR_EXCEPT( cd_ptr1->D_f() != D_f_return );
TEST_FOR_EXCEPT( (*a_ptr1).A_g() != A_g_return );
TEST_FOR_EXCEPT( (*a_ptr1).A_f() != A_f_return );
TEST_FOR_EXCEPT( (*ca_ptr1).A_f() != A_f_return );
TEST_FOR_EXCEPT( (*d_ptr1).D_g() != D_g_return );
TEST_FOR_EXCEPT( (*d_ptr1).D_f() != D_f_return );
TEST_FOR_EXCEPT( (*cd_ptr1).D_f() != D_f_return );
const RefCountPtr<const B1> cb1_ptr1 = rcp_dynamic_cast<const B1>(ca_ptr1);
TEST_FOR_EXCEPT( cb1_ptr1.get() == NULL );
#ifndef __sun
TEST_FOR_EXCEPT( cb1_ptr1.count() != 3 );
TEST_FOR_EXCEPT( ca_ptr1.count() != 3 );
TEST_FOR_EXCEPT( a_ptr1.count() != 3 );
#endif
TEST_FOR_EXCEPT( rcp_implicit_cast<const A>(cb1_ptr1)->A_f() != A_f_return );
TEST_FOR_EXCEPT( RefCountPtr<const A>(cb1_ptr1)->A_f() != A_f_return );
TEST_FOR_EXCEPT( rcp_implicit_cast<const A>(a_ptr1)->A_f() != A_f_return );
TEST_FOR_EXCEPT( RefCountPtr<const A>(a_ptr1)->A_f() != A_f_return );
TEST_FOR_EXCEPT( rcp_const_cast<B1>(cb1_ptr1)->B1_g() != B1_g_return );
TEST_FOR_EXCEPT( rcp_dynamic_cast<const B2>(cb1_ptr1)->B2_f() != B2_f_return );
TEST_FOR_EXCEPT( rcp_dynamic_cast<const C>(cb1_ptr1)->C_f() != C_f_return );
const RefCountPtr<C>
c_ptr1 = rcp_const_cast<C>(rcp_dynamic_cast<const C>(ca_ptr1));
TEST_FOR_EXCEPT( c_ptr1.get() == NULL );
#ifndef __sun
TEST_FOR_EXCEPT( c_ptr1.count() != 4 );
TEST_FOR_EXCEPT( ca_ptr1.count() != 4 );
TEST_FOR_EXCEPT( a_ptr1.count() != 4 );
#endif
const RefCountPtr<const E>
ce_ptr1 = rcp_static_cast<const E>(cd_ptr1);
TEST_FOR_EXCEPT( ce_ptr1.get() == NULL);
#ifndef __sun
TEST_FOR_EXCEPT( ce_ptr1.count() != 3 );
TEST_FOR_EXCEPT( cd_ptr1.count() != 3 );
TEST_FOR_EXCEPT( d_ptr1.count() != 3 );
#endif
TEST_FOR_EXCEPT( rcp_implicit_cast<const D>(ce_ptr1)->D_f() != D_f_return );
TEST_FOR_EXCEPT( rcp_const_cast<E>(ce_ptr1)->E_g() != E_g_return );
TEST_FOR_EXCEPT( ce_ptr1->D_f() != D_f_return );
#ifdef SHOW_COMPILE_TIME_ERRORS
rcp_dynamic_cast<const E>( cd_ptr1 )->E_f();
#endif
#ifndef _INTEL // Intel compiler does not seem to be doing dynamic cast correctly?
#ifdef TEUCHOS_DEBUG // operator->() only throws exception when TEUCHOS_DEBUG is defined
try {
TEST_FOR_EXCEPT( rcp_dynamic_cast<B1>( rcp(new B2) )->B1_g() != B1_g_return );
return -1;
}
catch( const std::logic_error &excpt )
{}
#endif
try {
rcp_dynamic_cast<B1>( rcp(new B2), true );
return -1;
}
catch( const std::bad_cast &excpt )
{}
#endif
delete d_ptr1.release();
#ifdef SHOW_RUN_TIME_ERROR_2
TEST_FOR_EXCEPT( d_ptr1->D_g() == D_g_return );
#endif
#ifdef SHOW_MEMORY_LEAK_1
a_ptr1.release();
#endif
}
#ifndef __sun
TEST_FOR_EXCEPT( a_ptr1.count() != 1 );
TEST_FOR_EXCEPT( d_ptr1.count() != 1 );
#endif
a_ptr1 = rcp(new A);
a_ptr1 = rcp(new B1);
a_ptr1 = rcp(new B2);
a_ptr1 = rcp(new C);
d_ptr1 = rcp(new D);
d_ptr1 = rcp(new E);
C c;
a_ptr1 = rcp(&c);
#ifndef SHOW_RUN_TIME_ERROR_3
a_ptr1.release();
#endif
E e;
d_ptr1 = rcp(&e);
#ifndef SHOW_RUN_TIME_ERROR_4
d_ptr1.release();
#endif
#ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
C *c_ptr5 = new C;
#ifdef SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
const void *c_ptr5_base = dynamic_cast<void*>(c_ptr5);
if(verbose) {
out << "\nSize of C = " << sizeof(C) << std::endl;
out << "Base address of object of type C = " << dynamic_cast<void*>(c_ptr5) << std::endl;
out << "Offset to address of object of type C = " << ((long int)c_ptr5 - (long int)c_ptr5_base) << std::endl;
out << "Offset of B1 object in object of type C = " << ((long int)static_cast<B1*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
out << "Offset of B2 object in object of type C = " << ((long int)static_cast<B2*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
out << "Offset of A object in object of type C = " << ((long int)static_cast<A*>(c_ptr5) - (long int)c_ptr5_base) << std::endl;
}
#endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS_PRINT
A *a_rptr5 = c_ptr5;
a_ptr1 = rcp(a_rptr5);
a_ptr1 = null;
#endif // SHOW_RUN_TIME_ERROR_VIRTUAL_BASE_CLASS
a_ptr1 = rcp( new C, DeallocDelete<C>(), true );
get_dealloc<DeallocDelete<C> >(a_ptr1);
TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<C> >(a_ptr1)==NULL );
TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<A> >(a_ptr1)!=NULL );
TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<C> >(const_cast<const RefCountPtr<A>&>(a_ptr1))==NULL );
TEST_FOR_EXCEPT( get_optional_dealloc<DeallocDelete<A> >(const_cast<const RefCountPtr<A>&>(a_ptr1))!=NULL );
TEST_FOR_EXCEPT( get_optional_extra_data<RefCountPtr<B1> >(a_ptr1,"blahblah") != NULL );
TEST_FOR_EXCEPT( get_optional_extra_data<int>(const_cast<const RefCountPtr<A>&>(a_ptr1),"blahblah") != NULL );
set_extra_data( int(-5), "int", &a_ptr1 );
TEST_FOR_EXCEPT( get_extra_data<int>(a_ptr1,"int") != -5 );
set_extra_data( rcp(new B1), "B1", &a_ptr1 );
TEST_FOR_EXCEPT( get_extra_data<RefCountPtr<B1> >(a_ptr1,"B1")->B1_f() != B1_f_return );
TEST_FOR_EXCEPT( get_extra_data<int>(const_cast<const RefCountPtr<A>&>(a_ptr1),"int") != -5 );
TEST_FOR_EXCEPT( (*get_optional_extra_data<RefCountPtr<B1> >(a_ptr1,"B1"))->B1_f() != B1_f_return );
TEST_FOR_EXCEPT( *get_optional_extra_data<int>(const_cast<const RefCountPtr<A>&>(a_ptr1),"int") != -5 );
TEST_FOR_EXCEPT( get_optional_extra_data<RefCountPtr<B1> >(a_ptr1,"blahblah") != NULL );
TEST_FOR_EXCEPT( get_optional_extra_data<int>(const_cast<const RefCountPtr<A>&>(a_ptr1),"blahblah") != NULL );
int a_f_return = -2;
set_extra_data( Teuchos::rcp(new Get_A_f_return(&*a_ptr1,&a_f_return)), "a_f_return", &a_ptr1, Teuchos::PRE_DESTROY );
a_ptr1 = null;
d_ptr1 = null;
#ifndef __sun
TEST_FOR_EXCEPT( a_f_return != A_f_return );
#endif
a_ptr1 = rcp( new C, deallocFunctorDelete<A>(deallocA), true );
a_ptr1 = null;
a_ptr1 = rcp( new C, deallocFunctorHandleDelete<A>(deallocHandleA), true );
a_ptr1 = null;
#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
if(verbose)
out << "\nCreate a circular reference that will case a memory leak! ...\n";
if(1) {
RefCountPtr<A> a = rcp(new A());
RefCountPtr<C> c = rcp(new C());
a->set_C(c);
c->set_A(a);
}
#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
#ifdef HAVE_TEUCHOS_BOOST
if(verbose)
out << "\nTesting basic RefCountPtr compatibility with boost::shared_ptr ...\n";
boost::shared_ptr<A> a_sptr1(new C());
RefCountPtr<A> a_rsptr1 = rcp(a_sptr1);
TEST_FOR_EXCEPT( a_rsptr1.get() != a_sptr1.get() );
boost::shared_ptr<A> a_sptr2 = shared_pointer(a_rsptr1);
TEST_FOR_EXCEPT( a_sptr2.get() != a_sptr1.get() );
RefCountPtr<A> a_rsptr2 = rcp(a_sptr2);
TEST_FOR_EXCEPT( a_rsptr2.get() != a_rsptr1.get() );
boost::shared_ptr<A> a_sptr3 = shared_pointer(a_rsptr2);
TEST_FOR_EXCEPT( a_sptr3.get() != a_rsptr2.get() );
#endif // HAVE_TEUCHOS_BOOST
if(verbose)
out << "\nAll tests for RefCountPtr seem to check out!\n";
}
TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose,std::cerr,success);
try {
Teuchos::PrivateUtilityPack::print_active_RefCountPtr_nodes(out);
}
TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose,std::cerr,success);
if(success)
out << "\nEnd Result: TEST PASSED" << std::endl;
return ( success ? 0 : 1 );
}