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

Generated on Thu Sep 18 12:30:30 2008 for Teuchos - Trilinos Tools Package by doxygen 1.3.9.1