// @HEADER // *********************************************************************** // // Teuchos: Common Tools Package // Copyright (2004) Sandia Corporation // // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive // license for use of this work by or on behalf of the U.S. Government. // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA // Questions? Contact Michael A. Heroux (maherou@sandia.gov) // // *********************************************************************** // @HEADER #ifndef TEUCHOS_ARRAY_RCP_HPP #define TEUCHOS_ARRAY_RCP_HPP #include "Teuchos_ArrayRCPDecl.hpp" #include "Teuchos_TestForException.hpp" #include "Teuchos_dyn_cast.hpp" #include "Teuchos_map.hpp" namespace Teuchos { // Constructors/Initializers template inline ArrayRCP::ArrayRCP( ENull ) : ptr_(NULL) , node_(NULL) , lowerOffset_(0) , upperOffset_(-1) {} template REFCOUNTPTR_INLINE ArrayRCP::ArrayRCP(const ArrayRCP& r_ptr) : ptr_(r_ptr.ptr_), node_(r_ptr.node_) , lowerOffset_(r_ptr.lowerOffset_) , upperOffset_(r_ptr.upperOffset_) { if(node_) node_->incr_count(); } template REFCOUNTPTR_INLINE ArrayRCP::~ArrayRCP() { if(node_ && node_->deincr_count() == 0 ) { #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES printActiveRCPNodes.foo(); // Make sure this object is used! remove_RCP_node(node_); #endif delete node_; } } template REFCOUNTPTR_INLINE ArrayRCP& ArrayRCP::operator=(const ArrayRCP& r_ptr) { if( this == &r_ptr ) return *this; // Assignment to self if( node_ && !node_->deincr_count() ) { #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES remove_RCP_node(node_); #endif delete node_; } ptr_ = r_ptr.ptr_; node_ = r_ptr.node_; lowerOffset_ = r_ptr.lowerOffset_; upperOffset_ = r_ptr.upperOffset_; if(node_) node_->incr_count(); return *this; } // Object/Pointer Access Functions template inline T* ArrayRCP::operator->() const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK assert_in_range(0,1); #endif return ptr_; } template inline T& ArrayRCP::operator*() const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK assert_in_range(0,1); #endif return *ptr_; } template inline T* ArrayRCP::get() const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK if(ptr_) { assert_in_range(0,1); } #endif return ptr_; } template REFCOUNTPTR_INLINE T& ArrayRCP::operator[](Ordinal offset) const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK assert_in_range(offset,1); #endif return ptr_[offset]; } // Pointer Arithmetic Functions template REFCOUNTPTR_INLINE ArrayRCP& ArrayRCP::operator++() { if(ptr_) { ++ptr_; --lowerOffset_; --upperOffset_; } return *this; } template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::operator++(int) { ArrayRCP r_ptr = *this; ++(*this); return r_ptr; } template REFCOUNTPTR_INLINE ArrayRCP& ArrayRCP::operator--() { if(ptr_) { --ptr_; ++lowerOffset_; ++upperOffset_; } return *this; } template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::operator--(int) { ArrayRCP r_ptr = *this; --(*this); return r_ptr; } template REFCOUNTPTR_INLINE ArrayRCP& ArrayRCP::operator+=(Ordinal offset) { if(ptr_) { ptr_ += offset; lowerOffset_ -= offset; upperOffset_ -= offset; } return *this; } template REFCOUNTPTR_INLINE ArrayRCP& ArrayRCP::operator-=(Ordinal offset) { if(ptr_) { ptr_ -= offset; lowerOffset_ += offset; upperOffset_ += offset; } return *this; } template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::operator+(Ordinal offset) const { ArrayRCP r_ptr = *this; r_ptr+=(offset); return r_ptr; } template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::operator-(Ordinal offset) const { ArrayRCP r_ptr = *this; r_ptr-=offset; return r_ptr; } // Views template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::getConst() const { const T *cptr = ptr_; // Will not compile if not legal! return ArrayRCP(cptr,lowerOffset_,upperOffset_,node_); } template REFCOUNTPTR_INLINE ArrayRCP ArrayRCP::subview( Ordinal lowerOffset, Ordinal size ) const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK assert_in_range(lowerOffset,size); #endif ArrayRCP ptr = *this; ptr.ptr_ = ptr.ptr_ + lowerOffset; ptr.lowerOffset_ = 0; ptr.upperOffset_ = size-1; return ptr; } // General query functions template REFCOUNTPTR_INLINE int ArrayRCP::count() const { if(node_) return node_->count(); return 0; } template REFCOUNTPTR_INLINE template bool ArrayRCP::shares_resource(const ArrayRCP& r_ptr) const { return node_ == r_ptr.access_node(); // Note: above, r_ptr is *not* the same class type as *this so we can not // access its node_ member directly! This is an interesting detail to the // C++ protected/private protection mechanism! } template REFCOUNTPTR_INLINE typename ArrayRCP::Ordinal ArrayRCP::lowerOffset() const { return lowerOffset_; } template REFCOUNTPTR_INLINE typename ArrayRCP::Ordinal ArrayRCP::upperOffset() const { return upperOffset_; } template REFCOUNTPTR_INLINE typename ArrayRCP::Ordinal ArrayRCP::size() const { return upperOffset_-lowerOffset_+1; } // Standard Container-Like Functions template REFCOUNTPTR_INLINE typename ArrayRCP::const_iterator ArrayRCP::begin() const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK return *this; #else return ptr_; #endif } template REFCOUNTPTR_INLINE typename ArrayRCP::const_iterator ArrayRCP::end() const { #ifdef HAVE_TEUCHOS_ARRAY_BOUNDSCHECK return *this + (upperOffset_ + 1); #else return ptr_ + (upperOffset_ + 1); #endif } // Ownership template REFCOUNTPTR_INLINE T* ArrayRCP::release() { if(node_) node_->has_ownership(false); return ptr_; } template REFCOUNTPTR_INLINE void ArrayRCP::set_has_ownership() { if(node_) node_->has_ownership(true); } template REFCOUNTPTR_INLINE bool ArrayRCP::has_ownership() const { if(node_) return node_->has_ownership(); return false; } // Assertion Functions. template inline const ArrayRCP& ArrayRCP::assert_not_null() const { if(!ptr_) PrivateUtilityPack::throw_null(TypeNameTraits::name()); return *this; } template inline const ArrayRCP& ArrayRCP::assert_in_range( Ordinal lowerOffset, Ordinal size ) const { assert_not_null(); TEST_FOR_EXCEPTION( !( lowerOffset_ <= lowerOffset && lowerOffset+size-1 <= upperOffset_ ), std::logic_error ,"Teuchos::ArrayRCP<"<::name()<<">::assert_in_range:" " Error, [lowerOffset,lowerOffset+size-1] = ["< inline ArrayRCP::ArrayRCP( T* p, Ordinal lowerOffset, Ordinal upperOffset, bool has_ownership ) : ptr_(p) , node_( p ? new PrivateUtilityPack::RCP_node_tmpl >( p,DeallocArrayDelete(),has_ownership ) : NULL ) ,lowerOffset_(lowerOffset) ,upperOffset_(upperOffset) { #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES if(node_) { std::ostringstream os; os << "{T=\'"<::name()<<"\',Concrete T=\'"< REFCOUNTPTR_INLINE template ArrayRCP::ArrayRCP( T* p, Ordinal lowerOffset, Ordinal upperOffset, Dealloc_T dealloc, bool has_ownership ) : ptr_(p) , node_( p ? new PrivateUtilityPack::RCP_node_tmpl(p,dealloc,has_ownership) : NULL ) ,lowerOffset_(lowerOffset) ,upperOffset_(upperOffset) { #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES if(node_) { std::ostringstream os; os << "{T=\'"<::name()<<"\',Concrete T=\'"< inline ArrayRCP::ArrayRCP( T* p, Ordinal lowerOffset, Ordinal upperOffset, node_t* node ) : ptr_(p) , node_(node) ,lowerOffset_(lowerOffset) ,upperOffset_(upperOffset) { if(node_) node_->incr_count(); } template inline T*& ArrayRCP::access_ptr() { return ptr_; } template inline T* ArrayRCP::access_ptr() const { return ptr_; } template inline typename ArrayRCP::node_t*& ArrayRCP::access_node() { return node_; } template inline typename ArrayRCP::node_t* ArrayRCP::access_node() const { return node_; } } // end namespace Teuchos // /////////////////////////////////////////// // Non-member functions for ArrayRCP namespace Teuchos { namespace Utilities { template inline void assert_shares_resource( const ArrayRCP &p1, const ArrayRCP &p2 ) { #ifdef TEUCHOS_DEBUG TEST_FOR_EXCEPT(!p1.shares_resource(p2)); #endif } } // namespace Utilities } // namespace Teuchos template inline Teuchos::ArrayRCP Teuchos::arcp( T* p, typename ArrayRCP::Ordinal lowerOffset ,typename ArrayRCP::Ordinal size ,bool owns_mem ) { return ArrayRCP(p,lowerOffset,lowerOffset+size-1,owns_mem); } template inline Teuchos::ArrayRCP Teuchos::arcp( T* p, typename ArrayRCP::Ordinal lowerOffset ,typename ArrayRCP::Ordinal size ,Dealloc_T dealloc, bool owns_mem ) { return ArrayRCP(p,lowerOffset,lowerOffset+size-1,dealloc,owns_mem); } template inline Teuchos::ArrayRCP Teuchos::arcp( typename ArrayRCP::Ordinal size ) { return ArrayRCP(new T[size],0,size-1,true); } template REFCOUNTPTR_INLINE Teuchos::ArrayRCP Teuchos::arcp( const RCP > &v ) { Teuchos::ArrayRCP ptr = arcp(&(*v)[0],0,v->size(),false); set_extra_data( v, "std::vector", &ptr ); return ptr; } template REFCOUNTPTR_INLINE Teuchos::RCP > Teuchos::get_std_vector( const ArrayRCP &ptr ) { return get_extra_data > >(ptr,"std::vector"); } template REFCOUNTPTR_INLINE Teuchos::ArrayRCP Teuchos::arcp( const RCP > &v ) { Teuchos::ArrayRCP ptr = arcp(&(*v)[0],0,v->size(),false); set_extra_data( v, "std::vector", &ptr ); return ptr; } template REFCOUNTPTR_INLINE Teuchos::RCP > Teuchos::get_std_vector( const ArrayRCP &ptr ) { return get_extra_data > >(ptr,"std::vector"); } template REFCOUNTPTR_INLINE bool Teuchos::is_null( const ArrayRCP &p ) { return p.access_ptr() == NULL; } template REFCOUNTPTR_INLINE bool Teuchos::operator==( const ArrayRCP &p, ENull ) { return p.access_ptr() == NULL; } template REFCOUNTPTR_INLINE bool Teuchos::operator!=( const ArrayRCP &p, ENull ) { return p.access_ptr() != NULL; } template REFCOUNTPTR_INLINE bool Teuchos::operator==( const ArrayRCP &p1, const ArrayRCP &p2 ) { return p1.access_ptr() == p2.access_ptr(); } template REFCOUNTPTR_INLINE bool Teuchos::operator!=( const ArrayRCP &p1, const ArrayRCP &p2 ) { return p1.access_ptr() != p2.access_ptr(); } template REFCOUNTPTR_INLINE bool Teuchos::operator<( const ArrayRCP &p1, const ArrayRCP &p2 ) { return p1.access_ptr() < p2.access_ptr(); } template REFCOUNTPTR_INLINE bool Teuchos::operator<=( const ArrayRCP &p1, const ArrayRCP &p2 ) { Utilities::assert_shares_resource(p1,p2); return p1.access_ptr() <= p2.access_ptr(); } template REFCOUNTPTR_INLINE bool Teuchos::operator>( const ArrayRCP &p1, const ArrayRCP &p2 ) { Utilities::assert_shares_resource(p1,p2); return p1.access_ptr() > p2.access_ptr(); } template REFCOUNTPTR_INLINE bool Teuchos::operator>=( const ArrayRCP &p1, const ArrayRCP &p2 ) { Utilities::assert_shares_resource(p1,p2); return p1.access_ptr() >= p2.access_ptr(); } template REFCOUNTPTR_INLINE Teuchos::ArrayRCP Teuchos::arcp_reinterpret_cast(const ArrayRCP& p1) { typedef typename ArrayRCP::Ordinal Ordinal; const int sizeOfT2ToT1 = sizeof(T2)/sizeof(T1); Ordinal lowerOffset2 = p1.lowerOffset() / sizeOfT2ToT1; Ordinal upperOffset2 = (p1.upperOffset()+1) / sizeOfT2ToT1 -1; T2 *ptr2 = reinterpret_cast(p1.get()); return ArrayRCP( ptr2,lowerOffset2,upperOffset2 ,p1.access_node() ); // Note: Above is just fine even if p1.get()==NULL! } template REFCOUNTPTR_INLINE Teuchos::ArrayRCP Teuchos::arcp_implicit_cast(const ArrayRCP& p1) { typedef typename ArrayRCP::Ordinal Ordinal; T2 * raw_ptr2 = p1.get(); return ArrayRCP( raw_ptr2,p1.lowerOffset(),p1.upperOffset() ,p1.access_node() ); // Note: Above is just fine even if p1.get()==NULL! } template REFCOUNTPTR_INLINE void Teuchos::set_extra_data( const T1 &extra_data, const std::string& name, Teuchos::ArrayRCP *p ,EPrePostDestruction destroy_when, bool force_unique ) { p->assert_not_null(); p->access_node()->set_extra_data( any(extra_data), name, destroy_when, force_unique ); } template REFCOUNTPTR_INLINE T1& Teuchos::get_extra_data( ArrayRCP& p, const std::string& name ) { p.assert_not_null(); return any_cast(p.access_node()->get_extra_data(TypeNameTraits::name(),name)); } template REFCOUNTPTR_INLINE const T1& Teuchos::get_extra_data( const ArrayRCP& p, const std::string& name ) { p.assert_not_null(); return any_cast(p.access_node()->get_extra_data(TypeNameTraits::name(),name)); } template REFCOUNTPTR_INLINE T1* Teuchos::get_optional_extra_data( ArrayRCP& p, const std::string& name ) { p.assert_not_null(); any *extra_data = p.access_node()->get_optional_extra_data(TypeNameTraits::name(),name); if( extra_data ) return &any_cast(*extra_data); return NULL; } template REFCOUNTPTR_INLINE const T1* Teuchos::get_optional_extra_data( const ArrayRCP& p, const std::string& name ) { p.assert_not_null(); any *extra_data = p.access_node()->get_optional_extra_data(TypeNameTraits::name(),name); if( extra_data ) return &any_cast(*extra_data); return NULL; } template REFCOUNTPTR_INLINE Dealloc_T& Teuchos::get_dealloc( ArrayRCP& p ) { typedef PrivateUtilityPack::RCP_node_tmpl requested_type; p.assert_not_null(); PrivateUtilityPack::RCP_node_tmpl *dnode = dynamic_cast*>(p.access_node()); TEST_FOR_EXCEPTION( dnode==NULL, std::logic_error ,"get_dealloc<" << TypeNameTraits::name() << "," << TypeNameTraits::name() << ">(p): " << "Error, requested type \'" << TypeNameTraits::name() << "\' does not match actual type of the node \'" << typeName(*p.access_node()) << "!" ); return dnode->get_dealloc(); } template inline const Dealloc_T& Teuchos::get_dealloc( const Teuchos::ArrayRCP& p ) { return get_dealloc(const_cast&>(p)); } template REFCOUNTPTR_INLINE Dealloc_T* Teuchos::get_optional_dealloc( ArrayRCP& p ) { p.assert_not_null(); typedef PrivateUtilityPack::RCP_node_tmpl RCPNT; RCPNT *dnode = dynamic_cast(p.access_node()); if(dnode) return &dnode->get_dealloc(); return NULL; } template inline const Dealloc_T* Teuchos::get_optional_dealloc( const Teuchos::ArrayRCP& p ) { return get_optional_dealloc(const_cast&>(p)); } template std::ostream& Teuchos::operator<<( std::ostream& out, const ArrayRCP& p ) { out << TypeNameTraits >::name() << "{" << "ptr="<<(const void*)(p.get()) // I can't find any alternative to this C cast :-( <<",lowerOffset="<