Teuchos_RCPNode.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_NODE_HPP
00030 #define TEUCHOS_RCP_NODE_HPP
00031 
00032 
00039 #include "Teuchos_ConfigDefs.hpp"
00040 #include "Teuchos_any.hpp"
00041 #include "Teuchos_map.hpp"
00042 #include "Teuchos_ENull.hpp"
00043 #include "Teuchos_Assert.hpp"
00044 #include "Teuchos_Exceptions.hpp"
00045 #include "Teuchos_toString.hpp"
00046 
00047 
00048 namespace Teuchos {
00049 
00050 
00055 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
00056 
00057 
00062 enum ERCPStrength { RCP_STRENGTH_INVALID=0, RCP_STRONG, RCP_WEAK };
00063 // Above: Making RCP_STRENGTH_INVALID=0 helps to avoid problems with
00064 // uninitialized memory that just happens to be zero! (see Code Complete: 2nd
00065 // Edition)
00066 
00067 
00068 template<>
00069 class ToStringTraits<ERCPStrength> {
00070 public:
00071   static std::string toString( const ERCPStrength &t )
00072     {
00073       switch (t) {
00074         case RCP_STRENGTH_INVALID:
00075           return "RCP_STRENGTH_INVALID";
00076         case RCP_STRONG:
00077           return "RCP_STRONG";
00078         case RCP_WEAK:
00079           return "RCP_STRONG";
00080         default:
00081           // Should never get here but fall through ...
00082           break;
00083       }
00084       // Should never get here!
00085 #ifdef TEUCHOS_DEBUG
00086       TEST_FOR_EXCEPT(true);
00087 #endif
00088       return "";
00089       // 2009/06/30: rabartl: The above logic avoid a warning from the Intel
00090       // 10.1 compiler (remark #111) about the statement being unreachable.
00091     }
00092 };
00093 
00094 
00095 
00104 class RCPNode {
00105 public:
00107   RCPNode(bool has_ownership_in)
00108     : strong_count_(1), weak_count_(0), has_ownership_(has_ownership_in),
00109       extra_data_map_(NULL)
00110     {}
00112   virtual ~RCPNode()
00113     {
00114       if(extra_data_map_)
00115         delete extra_data_map_;
00116     }
00118   int strong_count() const
00119     {
00120       return strong_count_; 
00121     }
00123   int weak_count() const
00124     {
00125       return weak_count_; 
00126     }
00128   int incr_count( const ERCPStrength strength )
00129     {
00130       switch (strength) {
00131         case RCP_STRONG:
00132           return ++strong_count_;
00133         case RCP_WEAK:
00134           return ++weak_count_;
00135         case RCP_STRENGTH_INVALID:
00136         default:
00137           TEST_FOR_EXCEPT(true);
00138       }
00139       return 0; // Never be called!
00140     }
00142   int deincr_count( const ERCPStrength strength )
00143     {
00144       switch (strength) {
00145         case RCP_STRONG:
00146           return --strong_count_;
00147         case RCP_WEAK:
00148           return --weak_count_;
00149         case RCP_STRENGTH_INVALID:
00150         default:
00151           TEST_FOR_EXCEPT(true);
00152       }
00153       return 0; // Never be called!
00154     }
00156   void has_ownership(bool has_ownership_in)
00157     {
00158       has_ownership_ = has_ownership_in;
00159     }
00161   bool has_ownership() const
00162     {
00163       return has_ownership_;
00164     }
00166   void set_extra_data(
00167     const any &extra_data, const std::string& name,
00168     EPrePostDestruction destroy_when, bool force_unique );
00170   any& get_extra_data( const std::string& type_name,
00171     const std::string& name );
00173   const any& get_extra_data( const std::string& type_name,
00174     const std::string& name
00175     ) const
00176     {
00177       return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
00178     }
00180   any* get_optional_extra_data(const std::string& type_name,
00181     const std::string& name );
00183   const any* get_optional_extra_data(
00184     const std::string& type_name, const std::string& name
00185     ) const
00186     {
00187       return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
00188     }
00190   virtual bool is_valid_ptr() const = 0;
00192   virtual void delete_obj() = 0;
00194   virtual void throw_invalid_obj_exception(
00195     const std::string& rcp_type_name,
00196     const void* rcp_ptr,
00197     const RCPNode* rcp_node_ptr,
00198     const void* rcp_obj_ptr
00199     ) const = 0;
00200 protected:
00202   void pre_delete_extra_data()
00203     {
00204       if(extra_data_map_)
00205         impl_pre_delete_extra_data();
00206     }
00207 private:
00208   struct extra_data_entry_t {
00209     extra_data_entry_t() : destroy_when(POST_DESTROY) {}
00210     extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
00211       : extra_data(_extra_data), destroy_when(_destroy_when)
00212       {}
00213     any extra_data;
00214     EPrePostDestruction destroy_when;
00215   }; 
00216   typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
00217   int strong_count_;
00218   int weak_count_;
00219   bool has_ownership_;
00220   extra_data_map_t *extra_data_map_;
00221   // Above is made a pointer to reduce overhead for the general case when this
00222   // is not used.  However, this adds just a little bit to the overhead when
00223   // it is used.
00224   // Provides the "basic" guarantee!
00225   void impl_pre_delete_extra_data();
00226   // Not defined and not to be called
00227   RCPNode();
00228   RCPNode(const RCPNode&);
00229   RCPNode& operator=(const RCPNode&);
00230 };
00231 
00232 
00237 template<class T, class Dealloc_T>
00238 class RCPNodeTmpl : public RCPNode {
00239 public:
00241   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
00242     : RCPNode(has_ownership_in), ptr_(p),
00243 #ifdef TEUCHOS_DEBUG
00244       deleted_ptr_(0),
00245 #endif
00246       dealloc_(dealloc)
00247     {}
00249   Dealloc_T& get_nonconst_dealloc()
00250     { return dealloc_; }
00252   const Dealloc_T& get_dealloc() const
00253     { return dealloc_; }
00255   ~RCPNodeTmpl()
00256     {
00257 #ifdef TEUCHOS_DEBUG
00258       TEST_FOR_EXCEPTION( ptr_!=0, std::logic_error,
00259         "Error, the underlying object must be explicitly deleted before deleting"
00260         " the node object!" );
00261 #endif
00262     }
00264   virtual bool is_valid_ptr() const
00265     {
00266       return ptr_ != 0;
00267     }
00273   virtual void delete_obj()
00274     {
00275       if (ptr_!= 0) {
00276         this->pre_delete_extra_data(); // May throw!
00277         T* tmp_ptr = ptr_;
00278 #ifdef TEUCHOS_DEBUG
00279         deleted_ptr_ = tmp_ptr;
00280 #endif
00281         ptr_ = 0;
00282         if (has_ownership()) {
00283 #ifdef TEUCHOS_DEBUG
00284           try {
00285 #endif
00286             dealloc_.free(tmp_ptr);
00287 #ifdef TEUCHOS_DEBUG
00288           }
00289           catch(...) {
00290             // Object was not deleted due to an exception!
00291             ptr_ = tmp_ptr;
00292             throw;
00293           }
00294 #endif
00295         }
00296         // 2008/09/22: rabartl: Above, we have to be careful to set the member
00297         // this->ptr_=0 before calling delete on the object's address in order
00298         // to avoid a double call to delete in cases of circular references
00299         // involving weak and strong pointers (see the unit test
00300         // circularReference_c_then_a in RCP_UnitTests.cpp).  NOTE: It is
00301         // critcial that no member of *this get accesses after
00302         // dealloc_.free(...) gets called!  Also, in order to provide the
00303         // "strong" guarantee we have to include the above try/catch.  This
00304         // overhead is unfortunate but I don't know of any other way to
00305         // statisfy the "strong" guarantee and still avoid a double delete.
00306       }
00307     }
00309   virtual void throw_invalid_obj_exception(
00310     const std::string& rcp_type_name,
00311     const void* rcp_ptr,
00312     const RCPNode* rcp_node_ptr,
00313     const void* rcp_obj_ptr
00314     ) const
00315     {
00316       TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
00317       const T* deleted_ptr =
00318 #ifdef TEUCHOS_DEBUG
00319         deleted_ptr_
00320 #else
00321         0
00322 #endif
00323         ;
00324       TEST_FOR_EXCEPTION( true, DanglingReferenceError,
00325         "Error, an attempt has been made to dereference the underlying object\n"
00326         "from a weak smart pointer object where the underling object has already\n"
00327         "been deleted since the strong count has already gone to zero.\n"
00328         "\n"
00329         "Context information:\n"
00330         "\n"
00331         "  RCP type:             " << rcp_type_name << "\n"
00332         "  RCP address:          " << rcp_ptr << "\n"
00333         "  RCPNode type:         " << typeName(*this) << "\n"
00334         "  RCPNode address       " << rcp_node_ptr << "\n"
00335         "  RCP ptr address:      " << rcp_obj_ptr << "\n"
00336         "  Concrete ptr address: " << deleted_ptr << "\n"
00337         "\n"
00338         "Hint: Open your debugger and set conditional breakpoints in the various\n"
00339         "routines involved where this node object is first created with this\n"
00340         "concrete object and in all of the RCP objects of the type given above\n"
00341         "use this node object.  Debugging an error like this may take a little work\n"
00342         "setting up your debugging session but at least you don't have to try to\n"
00343         "track down a segfault that would occur otherwise!"
00344         );
00345       // 2008/09/22: rabartl: Above, we do not provide the concreate object
00346       // type or the concrete object address.  In the case of the concrete
00347       // object address, in a non-debug build, we don't want to pay a price
00348       // for extra storage that we strictly don't need.  In the case of the
00349       // concrete object type name, we don't want to force non-debug built
00350       // code to have the require that types be fully defined in order to use
00351       // the memory management software.  This is related to bug 4016.
00352 
00353     }
00354 private:
00355   T *ptr_;
00356 #ifdef TEUCHOS_DEBUG
00357   T *deleted_ptr_;
00358 #endif
00359   Dealloc_T dealloc_;
00360   // not defined and not to be called
00361   RCPNodeTmpl();
00362   RCPNodeTmpl(const RCPNodeTmpl&);
00363   RCPNodeTmpl& operator=(const RCPNodeTmpl&);
00364 
00365 }; // end class RCPNodeTmpl<T>
00366 
00367 
00372 void add_new_RCPNode( RCPNode* rcp_node, const std::string &info );
00373 
00374 
00379 void remove_RCPNode( RCPNode* rcp_node );
00380 
00381 
00386 class PrintActiveRCPNodes {
00387 public:
00389   PrintActiveRCPNodes();
00391   ~PrintActiveRCPNodes();
00393   void foo();
00394 private:
00395   static int count_;
00396 };
00397 
00398 
00406 bool isTracingActiveRCPNodes();
00407 
00408 
00409 #ifdef TEUCHOS_DEBUG
00410 
00424 void setTracingActiveRCPNodes(bool tracingActiveNodes);
00425 
00426 #endif // TEUCHOS_DEBUG
00427 
00428 
00430 int numActiveRCPNodes();
00431 
00432 
00449 void printActiveRCPNodes(std::ostream &out);
00450 
00451 
00453 void throw_null_ptr_error( const std::string &type_name );
00454 
00455 
00456 } // namespace Teuchos
00457 
00458 
00459 namespace {
00460 // This static variable should be delcared before all other static variables
00461 // that depend on RCP or other classes. Therefore, this static varaible should
00462 // be deleted *after* all of these other static variables that depend on RCP
00463 // or created classes go away!
00464 Teuchos::PrintActiveRCPNodes local_printActiveRCPNodes;
00465 } // namespace
00466 
00467 
00468 namespace Teuchos {
00469 
00470 
00484 class RCPNodeHandle {
00485 public:
00487   RCPNodeHandle( ENull null_arg = null )
00488     : node_(0), strength_(RCP_STRENGTH_INVALID)
00489     {(void)null_arg;}
00491   RCPNodeHandle( RCPNode* node, ERCPStrength strength_in = RCP_STRONG )
00492     : node_(node), strength_(strength_in)
00493     {}
00494 #ifdef TEUCHOS_DEBUG
00495 
00496   template<typename T>
00497   RCPNodeHandle( RCPNode* node, T *p, const std::string &T_name,
00498     const std::string &ConcreateT_name, const bool has_ownership_in,
00499     ERCPStrength strength_in = RCP_STRONG
00500     )
00501     : node_(node), strength_(strength_in)
00502     {
00503       TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle yet!
00504       TEUCHOS_ASSERT(node_);
00505       if (isTracingActiveRCPNodes()) {
00506         std::ostringstream os;
00507         os << "{T=\'"<<T_name<<"\',Concrete T=\'"
00508            <<ConcreateT_name<<"\',p="<<p<<",has_ownership="<<has_ownership_in<<"}";
00509         add_new_RCPNode(node_, os.str());
00510       }
00511     }
00512 #endif // TEUCHOS_DEBUG
00513 
00514   RCPNodeHandle( const RCPNodeHandle& node_ref )
00515     : node_(node_ref.node_), strength_(node_ref.strength_)
00516     {
00517       if (node_)
00518         node_->incr_count(strength_);
00519     }
00521   RCPNodeHandle& operator=( const RCPNodeHandle& node_ref )
00522     {
00523       // Assignment to self check
00524       if ( this == &node_ref )
00525         return *this;
00526       // Take care of this's existing node and object
00527       unbind(); // May throw in some cases
00528       // Assign the new node
00529       node_ = node_ref.node_;
00530       strength_ = node_ref.strength_;
00531       if (node_)
00532         node_->incr_count(strength_);
00533       return *this;
00534     }
00536   ~RCPNodeHandle()
00537     {
00538       unbind();
00539     }
00541   RCPNodeHandle create_weak() const
00542     {
00543       if (node_) {
00544         node_->incr_count(RCP_WEAK);
00545         return RCPNodeHandle(node_, RCP_WEAK);
00546       }
00547       return RCPNodeHandle();
00548     }
00550   RCPNodeHandle create_strong() const
00551     {
00552       if (node_) {
00553         node_->incr_count(RCP_STRONG);
00554         return RCPNodeHandle(node_, RCP_STRONG);
00555       }
00556       return RCPNodeHandle();
00557     }
00559   RCPNode* node_ptr() const
00560     {
00561       return node_;
00562     }
00564   bool is_node_null() const
00565     {
00566       return node_==0;
00567     }
00569   bool is_valid_ptr() const
00570     {
00571       if (node_)
00572         return node_->is_valid_ptr();
00573       return true; // Null is a valid ptr!
00574     }
00576   bool same_node(const RCPNodeHandle &node2) const
00577     {
00578       return node_ == node2.node_;
00579     }
00581   int strong_count() const
00582     {
00583       if (node_)
00584         return node_->strong_count(); 
00585       return 0;
00586     }
00588   int weak_count() const
00589     {
00590       if (node_)
00591         return node_->weak_count(); 
00592       return 0;
00593     }
00595   int total_count() const
00596     {
00597       if (node_)
00598         return node_->strong_count() + node_->weak_count(); 
00599       return 0;
00600     }
00602   int count() const
00603     {
00604       if (node_)
00605         return node_->strong_count(); 
00606       return 0;
00607     }
00609   ERCPStrength strength() const
00610     {
00611       return strength_;
00612     }
00614   void has_ownership(bool has_ownership_in)
00615     {
00616       if (node_)
00617         node_->has_ownership(has_ownership_in);
00618     }
00620   bool has_ownership() const
00621     {
00622       if (node_)
00623         return node_->has_ownership();
00624       return false;
00625     }
00627   void set_extra_data(
00628     const any &extra_data, const std::string& name,
00629     EPrePostDestruction destroy_when, bool force_unique
00630     )
00631     {
00632       debug_assert_not_null();
00633       node_->set_extra_data(extra_data, name, destroy_when, force_unique);
00634     }
00636   any& get_extra_data( const std::string& type_name,
00637     const std::string& name
00638     )
00639     {
00640       debug_assert_not_null();
00641       return node_->get_extra_data(type_name, name);
00642     } 
00644   const any& get_extra_data( const std::string& type_name,
00645     const std::string& name 
00646     ) const
00647     {
00648       return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
00649     }
00651   any* get_optional_extra_data(
00652     const std::string& type_name, const std::string& name
00653     )
00654     {
00655       debug_assert_not_null();
00656       return node_->get_optional_extra_data(type_name, name);
00657     } 
00659   const any* get_optional_extra_data(
00660     const std::string& type_name, const std::string& name
00661     ) const
00662     {
00663       return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
00664     }
00666   void debug_assert_not_null() const
00667     {
00668 #ifdef TEUCHOS_DEBUG
00669       if (!node_)
00670         throw_null_ptr_error(typeName(*this));
00671 #endif
00672     }
00674   template<class RCPType>
00675   void assert_valid_ptr(const RCPType& rcp_obj) const
00676     {
00677       if (!node_)
00678         return; // Null is a valid pointer!
00679       if (!is_valid_ptr()) {
00680         node_->throw_invalid_obj_exception( typeName(rcp_obj),
00681           this, node_, rcp_obj.access_private_ptr() );
00682       }
00683     }
00685   template<class RCPType>
00686   void debug_assert_valid_ptr(const RCPType& rcp_obj) const
00687     {
00688 #ifdef TEUCHOS_DEBUG
00689       assert_valid_ptr(rcp_obj);
00690 #endif
00691     }
00692 private:
00693   RCPNode *node_;
00694   ERCPStrength strength_;
00695   // Provides the "strong" guarantee!
00696   void unbind()
00697     {
00698       if (node_) {
00699         // NOTE: We only deincrement the reference count after
00700         // we have called delete on the underlying object since
00701         // that call to delete may actually thrown an exception!
00702         if (node_->strong_count()==1 && strength()==RCP_STRONG) {
00703           // Delete the object (which might throw)
00704           node_->delete_obj();
00705         }
00706         // If we get here, no exception was thrown!
00707         if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
00708           // The last RCP object is going away so time to delete
00709           // the entire node!
00710 #ifdef TEUCHOS_DEBUG
00711           local_printActiveRCPNodes.foo(); // Make sure created!
00712           remove_RCPNode(node_);
00713 #endif
00714           delete node_;
00715           node_ = 0;
00716           // NOTE: No need to deincrement the reference count since this is
00717           // the last RCP object being deleted!
00718         }
00719         else {
00720           // The last RCP has not gone away so just deincrement the reference
00721           // count.
00722           node_->deincr_count(strength());
00723         }
00724       }
00725     }
00726 };
00727 
00728 
00733 inline
00734 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
00735 {
00736   out << node.node_ptr();
00737   return out;
00738 }
00739 
00740 
00741 } // end namespace Teuchos
00742 
00743 
00744 #endif // TEUCHOS_RCP_NODE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Tue Oct 20 10:14:00 2009 for Teuchos Package Browser (Single Doxygen Collection) by  doxygen 1.6.1