Teuchos_RCP.hpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #ifndef TEUCHOS_RCP_HPP
00030 #define TEUCHOS_RCP_HPP
00031 
00042 #include "Teuchos_RCPDecl.hpp"
00043 #include "Teuchos_TestForException.hpp"
00044 #include "Teuchos_dyn_cast.hpp"
00045 #include "Teuchos_map.hpp"
00046 #include "Teuchos_TypeNameTraits.hpp"
00047 
00048 //#define TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES // Define this on command line to keep track of this!
00049 
00050 // /////////////////////////////////////////////////////////////////////////
00051 // Inline implementations below, not for the client to look at.
00052 
00053 namespace Teuchos {
00054 
00055 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00056 
00057 namespace PrivateUtilityPack {
00058 
00059 //
00060 class RCP_node;
00061 
00062 // Assert that the pointer is not null
00063 void throw_null( const std::string &type_name );
00064 
00065 // Node class to keep track of the delete address and
00066 // the reference count for RCP<...>
00067 class RCP_node {
00068 public:
00069   RCP_node(bool has_ownership)
00070     : count_(1), has_ownership_(has_ownership), extra_data_map_(NULL)
00071   {}
00072   virtual ~RCP_node()
00073   {
00074     if(extra_data_map_) delete extra_data_map_;
00075   }
00076   int count() const {
00077     return count_;  
00078   }
00079   int incr_count() {
00080     return ++count_;
00081   }
00082   int deincr_count() {
00083     return --count_;
00084   }
00085   void has_ownership(bool has_ownership) {
00086     has_ownership_ = has_ownership;
00087   }
00088   bool has_ownership() const {
00089     return has_ownership_;
00090   }
00091   void set_extra_data( const any &extra_data, const std::string& name, EPrePostDestruction destroy_when, bool force_unique );
00092   any& get_extra_data( const std::string& type_name, const std::string& name );
00093   const any& get_extra_data( const std::string& type_name, const std::string& name ) const {
00094     return const_cast<RCP_node*>(this)->get_extra_data(type_name,name);
00095   }
00096   any* get_optional_extra_data( const std::string& type_name, const std::string& name );
00097   const any* get_optional_extra_data( const std::string& type_name, const std::string& name ) const {
00098     return const_cast<RCP_node*>(this)->get_optional_extra_data(type_name,name);
00099   }
00100 protected:
00101   void pre_delete_extra_data() {
00102     if(extra_data_map_) impl_pre_delete_extra_data();
00103   }
00104 private:
00105   struct extra_data_entry_t {
00106     extra_data_entry_t() : destroy_when(POST_DESTROY) {}
00107     extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
00108       : extra_data(_extra_data), destroy_when(_destroy_when) {}
00109     any extra_data;
00110     EPrePostDestruction destroy_when;
00111   };  
00112   typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
00113   int                 count_;
00114   bool                has_ownership_;
00115   extra_data_map_t    *extra_data_map_;
00116   // Above is made a pointer to reduce overhead for the general case
00117   // where this is not used
00118   void impl_pre_delete_extra_data();
00119   // Not defined and not to be called
00120   RCP_node();
00121   RCP_node(const RCP_node&);
00122   RCP_node& operator=(const RCP_node&);
00123 };  // end class RCP_node;
00124 
00125 // Implementation class for actually deleting the object if has_ownership() == true.
00126 template<class T, class Dealloc_T>
00127 class RCP_node_tmpl : public RCP_node {
00128 public:
00129 
00130   //
00131   RCP_node_tmpl(T* p, Dealloc_T dealloc, bool has_ownership)
00132     : RCP_node(has_ownership), ptr_(p), dealloc_(dealloc)
00133   {}
00134   //
00135   Dealloc_T& get_dealloc() { return dealloc_; }
00136   //
00137   const Dealloc_T& get_dealloc() const { return dealloc_; }
00138   //
00139   ~RCP_node_tmpl() {
00140     this->pre_delete_extra_data();
00141     if( has_ownership() )
00142       dealloc_.free(ptr_);
00143   }
00144 
00145 private:
00146 
00147   T           *ptr_;
00148   Dealloc_T   dealloc_;
00149   // not defined and not to be called
00150   RCP_node_tmpl();
00151   RCP_node_tmpl(const RCP_node_tmpl&);
00152   RCP_node_tmpl& operator=(const RCP_node_tmpl&);
00153 
00154 }; // end class RCP_node_tmpl<T>
00155 
00156 // Add new RCP to global list
00157 void add_new_RCP_node( RCP_node* rcp_node, const std::string &info );
00158 
00159 // Remove RCP from global list
00160 void remove_RCP_node( RCP_node* rcp_node );
00161 
00162 // Print global list on destruction
00163 class PrintActiveRCPNodes {
00164 public:
00165   PrintActiveRCPNodes();
00166   ~PrintActiveRCPNodes();
00167   void foo();
00168 private:
00169   static int count_;
00170 };
00171 
00172 }  // end namespace PrivateUtilityPack 
00173 
00174 } // namespace Teuchos
00175 
00176 namespace {
00177 // This static variable should be delcared before all other static variables
00178 // that depend on RCP and therefore This static varaible should be
00179 // deleted *after* all of these other static variables that depend on
00180 // RCP go away!
00181 Teuchos::PrivateUtilityPack::PrintActiveRCPNodes printActiveRCPNodes;
00182 } // namespace
00183 
00184 #endif // DOXYGEN_SHOULD_SKIP_THIS
00185 
00186 
00187 namespace Teuchos {
00188 
00189 
00190 // /////////////////////////////////////////////////////////////////////////////////
00191 // Inline member functions for RCP<...>.
00192 
00193 template<class T>
00194 inline
00195 RCP<T>::RCP( ENull )
00196   : ptr_(NULL)
00197   , node_(NULL)
00198 {}
00199 
00200 template<class T>
00201 REFCOUNTPTR_INLINE
00202 RCP<T>::RCP(const RCP<T>& r_ptr)
00203   : ptr_(r_ptr.ptr_), node_(r_ptr.node_)
00204 {
00205   if(node_) node_->incr_count();
00206 }
00207 
00208 template<class T>
00209 REFCOUNTPTR_INLINE
00210 template <class T2>
00211 RCP<T>::RCP(const RCP<T2>& r_ptr)
00212   : ptr_(const_cast<T2*>(r_ptr.get()))                 // will not compile if T1 is not an ancestor of T2
00213   , node_(const_cast<node_t*>(r_ptr.access_node()))
00214 {
00215   if(node_) node_->incr_count();
00216 }
00217 
00218 template<class T>
00219 REFCOUNTPTR_INLINE
00220 RCP<T>::~RCP()
00221 {
00222   if(node_ && node_->deincr_count() == 0 ) {
00223 #ifdef TEUCHOS_DEBUG
00224     printActiveRCPNodes.foo(); // Make sure this object is used!
00225     remove_RCP_node(node_);
00226 #endif
00227     delete node_;
00228   }
00229 }
00230 
00231 template<class T>
00232 REFCOUNTPTR_INLINE
00233 RCP<T>& RCP<T>::operator=(const RCP<T>& r_ptr)
00234 {
00235   if( this == &r_ptr )
00236     return *this; // Assignment to self
00237   if( node_ && !node_->deincr_count() ) {
00238 #ifdef TEUCHOS_DEBUG
00239     remove_RCP_node(node_);
00240 #endif
00241     delete node_;
00242   }
00243   ptr_  = r_ptr.ptr_;
00244   node_ = r_ptr.node_;
00245   if(node_) node_->incr_count();
00246   return *this;
00247 }
00248 
00249 template<class T>
00250 inline
00251 T* RCP<T>::operator->() const {
00252 #ifdef TEUCHOS_REFCOUNTPTR_ASSERT_NONNULL
00253   assert_not_null();
00254 #endif
00255   return ptr_;
00256 }
00257 
00258 template<class T>
00259 inline
00260 T& RCP<T>::operator*() const {
00261 #ifdef TEUCHOS_REFCOUNTPTR_ASSERT_NONNULL
00262   assert_not_null();
00263 #endif
00264   return *ptr_;
00265 }
00266 
00267 template<class T>
00268 inline
00269 T* RCP<T>::get() const {
00270   return ptr_;
00271 }
00272 
00273 template<class T>
00274 REFCOUNTPTR_INLINE
00275 T* RCP<T>::release() {
00276   if(node_)
00277     node_->has_ownership(false);
00278   return ptr_;
00279 }
00280 
00281 template<class T>
00282 REFCOUNTPTR_INLINE
00283 int RCP<T>::count() const {
00284   if(node_)
00285     return node_->count();
00286   return 0;
00287 }
00288 
00289 template<class T>
00290 REFCOUNTPTR_INLINE
00291 void RCP<T>::set_has_ownership() {
00292   if(node_)
00293     node_->has_ownership(true);
00294 }
00295 
00296 template<class T>
00297 REFCOUNTPTR_INLINE
00298 bool RCP<T>::has_ownership() const {
00299   if(node_)
00300     return node_->has_ownership();
00301   return false;
00302 }
00303 
00304 template<class T>
00305 REFCOUNTPTR_INLINE
00306 template <class T2>
00307 bool RCP<T>::shares_resource(const RCP<T2>& r_ptr) const {
00308   return node_ == r_ptr.access_node();
00309   // Note: above, r_ptr is *not* the same class type as *this so we can not
00310   // access its node_ member directly!  This is an interesting detail to the
00311   // C++ protected/private protection mechanism!
00312 }
00313 
00314 template<class T>
00315 inline
00316 const RCP<T>& RCP<T>::assert_not_null() const {
00317   if(!ptr_) PrivateUtilityPack::throw_null(TypeNameTraits<T>::name());
00318   return *this;
00319 }
00320 
00321 // very bad public functions
00322 
00323 template<class T>
00324 inline
00325 RCP<T>::RCP( T* p, bool has_ownership )
00326   : ptr_(p)
00327   , node_( p ? new PrivateUtilityPack::RCP_node_tmpl<T,DeallocDelete<T> >(p,DeallocDelete<T>(),has_ownership) : NULL )
00328 {
00329 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
00330   if(node_) {
00331     std::ostringstream os;
00332     os << "{T=\'"<<TypeNameTraits<T>::name()<<"\',Concrete T=\'"<<typeName(*p)<<"\',p="<<p<<",has_ownership="<<has_ownership<<"}";
00333     add_new_RCP_node(node_,os.str());
00334   }
00335 #endif
00336 }
00337 
00338 template<class T>
00339 REFCOUNTPTR_INLINE
00340 template<class Dealloc_T>
00341 RCP<T>::RCP( T* p, Dealloc_T dealloc, bool has_ownership )
00342   : ptr_(p)
00343   , node_( p ? new PrivateUtilityPack::RCP_node_tmpl<T,Dealloc_T>(p,dealloc,has_ownership) : NULL )
00344 {
00345 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODES
00346   if(node_) {
00347     std::ostringstream os;
00348     os << "{T=\'"<<TypeNameTraits<T>::name()<<"\',Concrete T=\'"<<typeName(*p)<<"\',p="<<p<<",has_ownership="<<has_ownership<<"}";
00349     add_new_RCP_node(node_,os.str());
00350   }
00351 #endif
00352 }
00353 
00354 template<class T>
00355 inline
00356 RCP<T>::RCP( T* p, node_t* node)
00357   : ptr_(p), node_(node)
00358 {
00359   if(node_) node_->incr_count();
00360 }
00361 
00362 template<class T>
00363 inline
00364 T*& RCP<T>::access_ptr()
00365 {  return ptr_; }
00366 
00367 template<class T>
00368 inline
00369 typename RCP<T>::node_t*& RCP<T>::access_node()
00370 {  return node_; }
00371 
00372 template<class T>
00373 inline
00374 typename RCP<T>::node_t* RCP<T>::access_node() const
00375 {  return node_; }
00376 
00377 }  // end namespace Teuchos
00378 
00379 // /////////////////////////////////////////////////////////////////////////////////
00380 // Inline non-member functions for RCP
00381 
00382 template<class T>
00383 inline
00384 Teuchos::RCP<T>
00385 Teuchos::rcp( T* p, bool owns_mem )
00386 {
00387   return RCP<T>(p,owns_mem);
00388 }
00389 
00390 template<class T, class Dealloc_T>
00391 inline
00392 Teuchos::RCP<T>
00393 Teuchos::rcp( T* p, Dealloc_T dealloc, bool owns_mem )
00394 {
00395   return RCP<T>(p,dealloc,owns_mem);
00396 }
00397 
00398 template<class T>
00399 REFCOUNTPTR_INLINE
00400 bool Teuchos::is_null( const RCP<T> &p )
00401 {
00402   return p.get() == NULL;
00403 }
00404 
00405 template<class T>
00406 REFCOUNTPTR_INLINE
00407 bool Teuchos::operator==( const RCP<T> &p, ENull )
00408 {
00409   return p.get() == NULL;
00410 }
00411 
00412 template<class T>
00413 REFCOUNTPTR_INLINE
00414 bool Teuchos::operator!=( const RCP<T> &p, ENull )
00415 {
00416   return p.get() != NULL;
00417 }
00418 
00419 template<class T1, class T2>
00420 REFCOUNTPTR_INLINE
00421 bool Teuchos::operator==( const RCP<T1> &p1, const RCP<T2> &p2 )
00422 {
00423   return p1.access_node() == p2.access_node();
00424 }
00425 
00426 template<class T1, class T2>
00427 REFCOUNTPTR_INLINE
00428 bool Teuchos::operator!=( const RCP<T1> &p1, const RCP<T2> &p2 )
00429 {
00430   return p1.access_node() != p2.access_node();
00431 }
00432 
00433 template<class T2, class T1>
00434 REFCOUNTPTR_INLINE
00435 Teuchos::RCP<T2>
00436 Teuchos::rcp_implicit_cast(const RCP<T1>& p1)
00437 {
00438   T2 *check = p1.get();  // Make the compiler check if the conversion is legal
00439   RCP<T2> p2;
00440   if(p1.access_node()) {
00441     p2.access_ptr()  = check;
00442     p2.access_node() = const_cast<RCP<T1>&>(p1).access_node();
00443     p2.access_node()->incr_count();
00444   }
00445   return p2;
00446 }
00447 
00448 template<class T2, class T1>
00449 REFCOUNTPTR_INLINE
00450 Teuchos::RCP<T2>
00451 Teuchos::rcp_static_cast(const RCP<T1>& p1)
00452 {
00453   T2 *check = static_cast<T2*>(p1.get()); // Make the compiler check if the conversion is legal
00454   RCP<T2> p2;
00455   if(p1.access_node()) {
00456     p2.access_ptr()  = check;
00457     p2.access_node() = const_cast<RCP<T1>&>(p1).access_node();
00458     p2.access_node()->incr_count();
00459   }
00460   return p2;
00461 }
00462 
00463 template<class T2, class T1>
00464 REFCOUNTPTR_INLINE
00465 Teuchos::RCP<T2>
00466 Teuchos::rcp_const_cast(const RCP<T1>& p1)
00467 {
00468   T2 *check = const_cast<T2*>(p1.get()); // Make the compiler check if the conversion is legal
00469   RCP<T2> p2;
00470   if(p1.access_node()) {
00471     p2.access_ptr()  = check;
00472     p2.access_node() = const_cast<RCP<T1>&>(p1).access_node();
00473     p2.access_node()->incr_count();
00474   }
00475   return p2;
00476 }
00477 
00478 template<class T2, class T1>
00479 REFCOUNTPTR_INLINE
00480 Teuchos::RCP<T2>
00481 Teuchos::rcp_dynamic_cast(const RCP<T1>& p1, bool throw_on_fail)
00482 {
00483   RCP<T2> p2; // NULL by default
00484   if( p1.get() ) {
00485     T2 *check = NULL;
00486     if(throw_on_fail)
00487       check = &dyn_cast<T2>(*p1);
00488     else
00489       check = dynamic_cast<T2*>(p1.get()); // Make the compiler check if the conversion is legal
00490     if(check) {
00491       p2.access_ptr()  = check;
00492       p2.access_node() = const_cast<RCP<T1>&>(p1).access_node();
00493       p2.access_node()->incr_count();
00494     }
00495   }
00496   return p2;
00497 }
00498 
00499 template<class T1, class T2>
00500 REFCOUNTPTR_INLINE
00501 void Teuchos::set_extra_data( const T1 &extra_data, const std::string& name, Teuchos::RCP<T2> *p, EPrePostDestruction destroy_when, bool force_unique )
00502 {
00503   p->assert_not_null();
00504   p->access_node()->set_extra_data( any(extra_data), name, destroy_when, force_unique );
00505 }
00506 
00507 template<class T1, class T2>
00508 REFCOUNTPTR_INLINE
00509 T1& Teuchos::get_extra_data( RCP<T2>& p, const std::string& name )
00510 {
00511   p.assert_not_null();
00512   return any_cast<T1>(p.access_node()->get_extra_data(TypeNameTraits<T1>::name(),name));
00513 }
00514 
00515 template<class T1, class T2>
00516 REFCOUNTPTR_INLINE
00517 const T1& Teuchos::get_extra_data( const RCP<T2>& p, const std::string& name )
00518 {
00519   p.assert_not_null();
00520   return any_cast<T1>(p.access_node()->get_extra_data(TypeNameTraits<T1>::name(),name));
00521 }
00522 
00523 template<class T1, class T2>
00524 REFCOUNTPTR_INLINE
00525 T1* Teuchos::get_optional_extra_data( RCP<T2>& p, const std::string& name )
00526 {
00527   p.assert_not_null();
00528   any *extra_data = p.access_node()->get_optional_extra_data(TypeNameTraits<T1>::name(),name);
00529   if( extra_data ) return &any_cast<T1>(*extra_data);
00530   return NULL;
00531 }
00532 
00533 template<class T1, class T2>
00534 REFCOUNTPTR_INLINE
00535 const T1* Teuchos::get_optional_extra_data( const RCP<T2>& p, const std::string& name )
00536 {
00537   p.assert_not_null();
00538   any *extra_data = p.access_node()->get_optional_extra_data(TypeNameTraits<T1>::name(),name);
00539   if( extra_data ) return &any_cast<T1>(*extra_data);
00540   return NULL;
00541 }
00542 
00543 template<class Dealloc_T, class T>
00544 REFCOUNTPTR_INLINE
00545 Dealloc_T&
00546 Teuchos::get_dealloc( RCP<T>& p )
00547 {
00548   typedef PrivateUtilityPack::RCP_node_tmpl<typename Dealloc_T::ptr_t,Dealloc_T>  requested_type;
00549   p.assert_not_null();
00550   PrivateUtilityPack::RCP_node_tmpl<typename Dealloc_T::ptr_t,Dealloc_T>
00551     *dnode = dynamic_cast<PrivateUtilityPack::RCP_node_tmpl<typename Dealloc_T::ptr_t,Dealloc_T>*>(p.access_node());
00552   TEST_FOR_EXCEPTION(
00553     dnode==NULL, std::logic_error
00554     ,"get_dealloc<" << TypeNameTraits<Dealloc_T>::name() << "," << TypeNameTraits<T>::name() << ">(p): "
00555     << "Error, requested type \'" << TypeNameTraits<requested_type>::name()
00556     << "\' does not match actual type of the node \'" << typeName(*p.access_node()) << "!"
00557     );
00558   return dnode->get_dealloc();
00559 }
00560 
00561 template<class Dealloc_T, class T>
00562 inline
00563 const Dealloc_T& 
00564 Teuchos::get_dealloc( const Teuchos::RCP<T>& p )
00565 {
00566   return get_dealloc<Dealloc_T>(const_cast<RCP<T>&>(p));
00567 }
00568 
00569 template<class Dealloc_T, class T>
00570 REFCOUNTPTR_INLINE
00571 Dealloc_T*
00572 Teuchos::get_optional_dealloc( RCP<T>& p )
00573 {
00574   p.assert_not_null();
00575   PrivateUtilityPack::RCP_node_tmpl<typename Dealloc_T::ptr_t,Dealloc_T>
00576     *dnode = dynamic_cast<PrivateUtilityPack::RCP_node_tmpl<typename Dealloc_T::ptr_t,Dealloc_T>*>(p.access_node());
00577   if(dnode)
00578     return &dnode->get_dealloc();
00579   return NULL;
00580 }
00581 
00582 template<class Dealloc_T, class T>
00583 inline
00584 const Dealloc_T*
00585 Teuchos::get_optional_dealloc( const Teuchos::RCP<T>& p )
00586 {
00587   return get_optional_dealloc<Dealloc_T>(const_cast<RCP<T>&>(p));
00588 }
00589 
00590 template<class T>
00591 std::ostream& Teuchos::operator<<( std::ostream& out, const RCP<T>& p )
00592 {
00593   out
00594     << TypeNameTraits<RCP<T> >::name() << "{"
00595     << "ptr="<<(const void*)(p.get()) // I can't find any alternative to this C cast :-(
00596     <<",node="<<p.access_node()
00597     <<",count="<<p.count()
00598     <<"}";
00599   return out;
00600 }
00601 
00602 #endif // TEUCHOS_RCP_HPP

Generated on Tue Oct 20 12:45:26 2009 for Teuchos - Trilinos Tools Package by doxygen 1.4.7