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_TypeNameTraits.hpp"
00046 #include "Teuchos_toString.hpp"
00047 #include "Teuchos_getBaseObjVoidPtr.hpp"
00048 
00049 
00050 namespace Teuchos {
00051 
00052 
00057 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
00058 
00063 enum ERCPStrength { RCP_STRENGTH_INVALID=-1, RCP_STRONG=0, RCP_WEAK=1 };
00064 
00069 enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP };
00070 
00072 inline void debugAssertStrength(ERCPStrength strength)
00073 {
00074 #ifdef TEUCHOS_DEBUG
00075   switch (strength) {
00076     case RCP_STRONG:
00077       // fall through
00078     case RCP_WEAK:
00079       return; // Fine
00080     case RCP_STRENGTH_INVALID:
00081     default:
00082       TEST_FOR_EXCEPT(true);
00083   }
00084 #endif
00085 }
00086 
00092 template<>
00093 class TEUCHOS_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
00094 public:
00095   static std::string toString( const ERCPStrength &t )
00096     {
00097       switch (t) {
00098         case RCP_STRENGTH_INVALID:
00099           return "RCP_STRENGTH_INVALID";
00100         case RCP_STRONG:
00101           return "RCP_STRONG";
00102         case RCP_WEAK:
00103           return "RCP_STRONG";
00104         default:
00105           // Should never get here but fall through ...
00106           break;
00107       }
00108       // Should never get here!
00109 #ifdef TEUCHOS_DEBUG
00110       TEST_FOR_EXCEPT(true);
00111 #endif
00112       return "";
00113       // 2009/06/30: rabartl: The above logic avoid a warning from the Intel
00114       // 10.1 compiler (remark #111) about the statement being unreachable.
00115     }
00116 };
00117 
00118 
00130 class TEUCHOS_LIB_DLL_EXPORT RCPNode {
00131 public:
00133   RCPNode(bool has_ownership_in)
00134     : has_ownership_(has_ownership_in), extra_data_map_(NULL)
00135 #ifdef TEUCHOS_DEBUG
00136     ,insertion_number_(-1)
00137 #endif // TEUCHOS_DEBUG
00138     {
00139       count_[RCP_STRONG] = 0;
00140       count_[RCP_WEAK] = 0;
00141     }
00143   virtual ~RCPNode()
00144     {
00145       if(extra_data_map_)
00146         delete extra_data_map_;
00147     }
00149   int strong_count() const
00150     {
00151       return count_[RCP_STRONG]; 
00152     }
00154   int weak_count() const
00155     {
00156       return count_[RCP_WEAK];
00157     }
00159   int count( const ERCPStrength strength )
00160     {
00161       debugAssertStrength(strength);
00162       return count_[strength];
00163     }
00165   int incr_count( const ERCPStrength strength )
00166     {
00167       debugAssertStrength(strength);
00168       return ++count_[strength];
00169     }
00171   int deincr_count( const ERCPStrength strength )
00172     {
00173       debugAssertStrength(strength);
00174       return --count_[strength];
00175     }
00177   void has_ownership(bool has_ownership_in)
00178     {
00179       has_ownership_ = has_ownership_in;
00180     }
00182   bool has_ownership() const
00183     {
00184       return has_ownership_;
00185     }
00187   void set_extra_data(
00188     const any &extra_data, const std::string& name,
00189     EPrePostDestruction destroy_when, bool force_unique );
00191   any& get_extra_data( const std::string& type_name,
00192     const std::string& name );
00194   const any& get_extra_data( const std::string& type_name,
00195     const std::string& name
00196     ) const
00197     {
00198       return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
00199     }
00201   any* get_optional_extra_data(const std::string& type_name,
00202     const std::string& name );
00204   const any* get_optional_extra_data(
00205     const std::string& type_name, const std::string& name
00206     ) const
00207     {
00208       return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
00209     }
00211   virtual bool is_valid_ptr() const = 0;
00213   virtual void delete_obj() = 0;
00215   virtual void throw_invalid_obj_exception(
00216     const std::string& rcp_type_name,
00217     const void* rcp_ptr,
00218     const RCPNode* rcp_node_ptr,
00219     const void* rcp_obj_ptr
00220     ) const = 0;
00222   virtual const std::string get_base_obj_type_name() const = 0;
00223 #ifdef TEUCHOS_DEBUG
00224 
00225   virtual const void* get_base_obj_map_key_void_ptr() const = 0;
00226 #endif
00227 protected:
00229   void pre_delete_extra_data()
00230     {
00231       if(extra_data_map_)
00232         impl_pre_delete_extra_data();
00233     }
00234 private:
00235   struct extra_data_entry_t {
00236     extra_data_entry_t() : destroy_when(POST_DESTROY) {}
00237     extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
00238       : extra_data(_extra_data), destroy_when(_destroy_when)
00239       {}
00240     any extra_data;
00241     EPrePostDestruction destroy_when;
00242   }; 
00243   typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
00244   int count_[2];
00245   bool has_ownership_;
00246   extra_data_map_t *extra_data_map_;
00247   // Above is made a pointer to reduce overhead for the general case when this
00248   // is not used.  However, this adds just a little bit to the overhead when
00249   // it is used.
00250   // Provides the "basic" guarantee!
00251   void impl_pre_delete_extra_data();
00252   // Not defined and not to be called
00253   RCPNode();
00254   RCPNode(const RCPNode&);
00255   RCPNode& operator=(const RCPNode&);
00256 #ifdef TEUCHOS_DEBUG
00257   int insertion_number_;
00258 public:
00259   void set_insertion_number(int insertion_number_in)
00260     {
00261       insertion_number_ = insertion_number_in;
00262     }
00263   int insertion_number() const
00264     {
00265       return insertion_number_;
00266     }
00267 #endif // TEUCHOS_DEBUG
00268 };
00269 
00270 
00275 TEUCHOS_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
00276 
00277 
00294 class RCPNodeTracer {
00295 public:
00296 
00299 
00301   struct RCPNodeStatistics {
00302     RCPNodeStatistics()
00303       : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
00304         totalNumRCPNodeDeletions(0)
00305       {}
00306     long int maxNumRCPNodes;
00307     long int totalNumRCPNodeAllocations;
00308     long int totalNumRCPNodeDeletions;
00309   };
00310 
00312 
00315 
00321   static TEUCHOS_LIB_DLL_EXPORT bool isTracingActiveRCPNodes();
00322 
00323 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00324 
00341   static TEUCHOS_LIB_DLL_EXPORT void setTracingActiveRCPNodes(bool tracingActiveNodes);
00342 #endif
00343 
00347   static TEUCHOS_LIB_DLL_EXPORT int numActiveRCPNodes();
00348 
00350   static TEUCHOS_LIB_DLL_EXPORT RCPNodeStatistics getRCPNodeStatistics() ;
00351 
00353   static TEUCHOS_LIB_DLL_EXPORT void printRCPNodeStatistics(
00354     const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
00355 
00359   static TEUCHOS_LIB_DLL_EXPORT void setPrintRCPNodeStatisticsOnExit(
00360     bool printRCPNodeStatisticsOnExit);
00361 
00365   static TEUCHOS_LIB_DLL_EXPORT bool getPrintRCPNodeStatisticsOnExit();
00366 
00381   static TEUCHOS_LIB_DLL_EXPORT void printActiveRCPNodes(std::ostream &out);
00382 
00384 
00389 
00394   static TEUCHOS_LIB_DLL_EXPORT void addNewRCPNode(RCPNode* rcp_node,
00395     const std::string &info );
00396 
00402   static TEUCHOS_LIB_DLL_EXPORT void removeRCPNode( RCPNode* rcp_node );
00403 
00412   template<class T>
00413   static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
00414     {
00415 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
00416       return getBaseObjVoidPtr(p);
00417 #else
00418       // This will not return the base address for polymorphic types if
00419       // multiple inheritance and/or virtual bases are used but returning the
00420       // static_cast should be okay in how it is used.  It is just that the
00421       // RCPNode tracing support will not always be able to figure out if two
00422       // pointers of different type are pointing to the same object or not.
00423       return static_cast<const void*>(p);
00424 #endif
00425     }
00426 
00433   static TEUCHOS_LIB_DLL_EXPORT RCPNode* getExistingRCPNodeGivenLookupKey(
00434     const void* lookupKey);
00435 
00442   template<class T>
00443   static RCPNode* getExistingRCPNode(T *p)
00444     {
00445       return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
00446     }
00447 
00449   static TEUCHOS_LIB_DLL_EXPORT std::string getActiveRCPNodeHeaderString();
00450 
00452   static TEUCHOS_LIB_DLL_EXPORT std::string getCommonDebugNotesString();
00453 
00455 
00456 };
00457 
00458 
00459 #ifdef TEUCHOS_DEBUG
00460 #  define TEUCHOS_RCP_INSERION_NUMBER_STR() \
00461       "  insertionNumber:      " << rcp_node_ptr->insertion_number() << "\n"
00462 #else
00463 #  define TEUCHOS_RCP_INSERION_NUMBER_STR()
00464 #endif
00465 
00466 
00472 template<class T, class Dealloc_T>
00473 class RCPNodeTmpl : public RCPNode {
00474 public:
00476   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
00477     : RCPNode(has_ownership_in), ptr_(p),
00478 #ifdef TEUCHOS_DEBUG
00479       base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
00480       deleted_ptr_(0),
00481 #endif
00482       dealloc_(dealloc)
00483     {}
00485   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
00486     : RCPNode(has_ownership_in), ptr_(p),
00487 #ifdef TEUCHOS_DEBUG
00488       base_obj_map_key_void_ptr_(0),
00489       deleted_ptr_(0),
00490 #endif
00491       dealloc_(dealloc)
00492     {}
00494   Dealloc_T& get_nonconst_dealloc()
00495     { return dealloc_; }
00497   const Dealloc_T& get_dealloc() const
00498     { return dealloc_; }
00500   ~RCPNodeTmpl()
00501     {
00502 #ifdef TEUCHOS_DEBUG
00503       TEST_FOR_EXCEPTION( ptr_!=0, std::logic_error,
00504         "Error, the underlying object must be explicitly deleted before deleting"
00505         " the node object!" );
00506 #endif
00507     }
00509   virtual bool is_valid_ptr() const
00510     {
00511       return ptr_ != 0;
00512     }
00518   virtual void delete_obj()
00519     {
00520       if (ptr_!= 0) {
00521         this->pre_delete_extra_data(); // May throw!
00522         T* tmp_ptr = ptr_;
00523 #ifdef TEUCHOS_DEBUG
00524         deleted_ptr_ = tmp_ptr;
00525 #endif
00526         ptr_ = 0;
00527         if (has_ownership()) {
00528 #ifdef TEUCHOS_DEBUG
00529           try {
00530 #endif
00531             dealloc_.free(tmp_ptr);
00532 #ifdef TEUCHOS_DEBUG
00533           }
00534           catch(...) {
00535             // Object was not deleted due to an exception!
00536             ptr_ = tmp_ptr;
00537             throw;
00538           }
00539 #endif
00540         }
00541         // 2008/09/22: rabartl: Above, we have to be careful to set the member
00542         // this->ptr_=0 before calling delete on the object's address in order
00543         // to avoid a double call to delete in cases of circular references
00544         // involving weak and strong pointers (see the unit test
00545         // circularReference_c_then_a in RCP_UnitTests.cpp).  NOTE: It is
00546         // critcial that no member of *this get accesses after
00547         // dealloc_.free(...) gets called!  Also, in order to provide the
00548         // "strong" guarantee we have to include the above try/catch.  This
00549         // overhead is unfortunate but I don't know of any other way to
00550         // statisfy the "strong" guarantee and still avoid a double delete.
00551       }
00552     }
00554   virtual void throw_invalid_obj_exception(
00555     const std::string& rcp_type_name,
00556     const void* rcp_ptr,
00557     const RCPNode* rcp_node_ptr,
00558     const void* rcp_obj_ptr
00559     ) const
00560     {
00561       TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
00562       const T* deleted_ptr =
00563 #ifdef TEUCHOS_DEBUG
00564         deleted_ptr_
00565 #else
00566         0
00567 #endif
00568         ;
00569       TEUCHOS_ASSERT(rcp_node_ptr);
00570       TEST_FOR_EXCEPTION( true, DanglingReferenceError,
00571         "Error, an attempt has been made to dereference the underlying object\n"
00572         "from a weak smart pointer object where the underling object has already\n"
00573         "been deleted since the strong count has already gone to zero.\n"
00574         "\n"
00575         "Context information:\n"
00576         "\n"
00577         "  RCP type:             " << rcp_type_name << "\n"
00578         "  RCP address:          " << rcp_ptr << "\n"
00579         "  RCPNode type:         " << typeName(*this) << "\n"
00580         "  RCPNode address:      " << rcp_node_ptr << "\n"
00581         TEUCHOS_RCP_INSERION_NUMBER_STR()
00582         "  RCP ptr address:      " << rcp_obj_ptr << "\n"
00583         "  Concrete ptr address: " << deleted_ptr << "\n"
00584         "\n"
00585         << RCPNodeTracer::getCommonDebugNotesString()
00586         );
00587       // 2008/09/22: rabartl: Above, we do not provide the concreate object
00588       // type or the concrete object address.  In the case of the concrete
00589       // object address, in a non-debug build, we don't want to pay a price
00590       // for extra storage that we strictly don't need.  In the case of the
00591       // concrete object type name, we don't want to force non-debug built
00592       // code to have the require that types be fully defined in order to use
00593       // the memory management software.  This is related to bug 4016.
00594 
00595     }
00597   const std::string get_base_obj_type_name() const
00598     {
00599 #ifdef TEUCHOS_DEBUG
00600       return TypeNameTraits<T>::name();
00601 #else
00602       return "UnknownType";
00603 #endif
00604     }
00605 #ifdef TEUCHOS_DEBUG
00606 
00607   const void* get_base_obj_map_key_void_ptr() const
00608     {
00609       return base_obj_map_key_void_ptr_;
00610     }
00611 #endif
00612 private:
00613   T *ptr_;
00614 #ifdef TEUCHOS_DEBUG
00615   const void *base_obj_map_key_void_ptr_;
00616   T *deleted_ptr_;
00617 #endif
00618   Dealloc_T dealloc_;
00619   // not defined and not to be called
00620   RCPNodeTmpl();
00621   RCPNodeTmpl(const RCPNodeTmpl&);
00622   RCPNodeTmpl& operator=(const RCPNodeTmpl&);
00623 
00624 }; // end class RCPNodeTmpl<T>
00625 
00626 
00634 class TEUCHOS_LIB_DLL_EXPORT ActiveRCPNodesSetup {
00635 public:
00637   ActiveRCPNodesSetup();
00639   ~ActiveRCPNodesSetup();
00641   void foo();
00642 private:
00643   static int count_;
00644 };
00645 
00646 
00647 } // namespace Teuchos
00648 
00649 
00650 namespace {
00651 // This static variable is delcared before all other static variables that
00652 // depend on RCP or other classes. Therefore, this static varaible will be
00653 // deleted *after* all of these other static variables that depend on RCP or
00654 // created classes go away!  This ensures that the node tracing machinery is
00655 // setup and torn down correctly (this is the same trick used by the standard
00656 // stream objects in many compiler implementations).
00657 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
00658 } // namespace
00659 
00660 
00661 namespace Teuchos {
00662 
00663 
00679 class TEUCHOS_LIB_DLL_EXPORT RCPNodeHandle {
00680 public:
00682   RCPNodeHandle(ENull null_arg = null)
00683     : node_(0), strength_(RCP_STRENGTH_INVALID)
00684     {(void)null_arg;}
00686   RCPNodeHandle( RCPNode* node, ERCPStrength strength_in = RCP_STRONG,
00687     bool newNode = true
00688     )
00689     : node_(node), strength_(strength_in)
00690     {
00691 #ifdef TEUCHOS_DEBUG
00692       TEUCHOS_ASSERT(node);
00693 #endif
00694       bind();
00695 #ifdef TEUCHOS_DEBUG
00696       // Add the node if this is the first RCPNodeHandle to get it.  We have
00697       // to add it because unbind() will call the remove_RCPNode(...) function
00698       // and it needs to match when node tracing is on from the beginning.
00699       if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode)
00700       {
00701         std::ostringstream os;
00702         os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
00703            << " has_ownership="<<node_->has_ownership()<<"}";
00704         RCPNodeTracer::addNewRCPNode(node_, os.str());
00705       }
00706 #endif
00707     }
00708 #ifdef TEUCHOS_DEBUG
00709 
00710   template<typename T>
00711   RCPNodeHandle(RCPNode* node, T *p, const std::string &T_name,
00712     const std::string &ConcreteT_name, const bool has_ownership_in,
00713     ERCPStrength strength_in = RCP_STRONG
00714     )
00715     : node_(node), strength_(strength_in)
00716     {
00717       TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
00718       TEUCHOS_ASSERT(node_);
00719       bind();
00720       if (RCPNodeTracer::isTracingActiveRCPNodes()) {
00721         std::ostringstream os;
00722         os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
00723            <<", p="<<static_cast<const void*>(p)
00724            <<", has_ownership="<<has_ownership_in<<"}";
00725         RCPNodeTracer::addNewRCPNode(node_, os.str());
00726       }
00727     }
00728 #endif // TEUCHOS_DEBUG
00729 
00730   RCPNodeHandle(const RCPNodeHandle& node_ref)
00731     : node_(node_ref.node_), strength_(node_ref.strength_)
00732     {
00733       bind();
00734     }
00736   void swap( RCPNodeHandle& node_ref )
00737     {
00738       std::swap(node_ref.node_, node_);
00739       std::swap(node_ref.strength_, strength_);
00740     }
00742   RCPNodeHandle& operator=(const RCPNodeHandle& node_ref)
00743     {
00744       // Assignment to self check: Note, We don't need to do an assigment to
00745       // self check here because such a check is already done in the RCP and
00746       // ArrayRCP classes.
00747       // Take care of this's existing node and object
00748       unbind(); // May throw in some cases
00749       // Assign the new node
00750       node_ = node_ref.node_;
00751       strength_ = node_ref.strength_;
00752       bind();
00753       // Return
00754       return *this;
00755     }
00757   ~RCPNodeHandle()
00758     {
00759       unbind();
00760     }
00762   RCPNodeHandle create_weak() const
00763     {
00764       if (node_) {
00765         return RCPNodeHandle(node_, RCP_WEAK, false);
00766       }
00767       return RCPNodeHandle();
00768     }
00770   RCPNodeHandle create_strong() const
00771     {
00772       if (node_) {
00773         return RCPNodeHandle(node_, RCP_STRONG, false);
00774       }
00775       return RCPNodeHandle();
00776     }
00778   RCPNode* node_ptr() const
00779     {
00780       return node_;
00781     }
00783   bool is_node_null() const
00784     {
00785       return node_==0;
00786     }
00788   bool is_valid_ptr() const
00789     {
00790       if (node_)
00791         return node_->is_valid_ptr();
00792       return true; // Null is a valid ptr!
00793     }
00795   bool same_node(const RCPNodeHandle &node2) const
00796     {
00797       return node_ == node2.node_;
00798     }
00800   int strong_count() const
00801     {
00802       if (node_)
00803         return node_->strong_count(); 
00804       return 0;
00805     }
00807   int weak_count() const
00808     {
00809       if (node_)
00810         return node_->weak_count(); 
00811       return 0;
00812     }
00814   int total_count() const
00815     {
00816       if (node_)
00817         return node_->strong_count() + node_->weak_count(); 
00818       return 0;
00819     }
00821   int count() const
00822     {
00823       if (node_)
00824         return node_->strong_count(); 
00825       return 0;
00826     }
00828   ERCPStrength strength() const
00829     {
00830       return strength_;
00831     }
00833   void has_ownership(bool has_ownership_in)
00834     {
00835       if (node_)
00836         node_->has_ownership(has_ownership_in);
00837     }
00839   bool has_ownership() const
00840     {
00841       if (node_)
00842         return node_->has_ownership();
00843       return false;
00844     }
00846   void set_extra_data(
00847     const any &extra_data, const std::string& name,
00848     EPrePostDestruction destroy_when, bool force_unique
00849     )
00850     {
00851       debug_assert_not_null();
00852       node_->set_extra_data(extra_data, name, destroy_when, force_unique);
00853     }
00855   any& get_extra_data( const std::string& type_name,
00856     const std::string& name
00857     )
00858     {
00859       debug_assert_not_null();
00860       return node_->get_extra_data(type_name, name);
00861     } 
00863   const any& get_extra_data( const std::string& type_name,
00864     const std::string& name 
00865     ) const
00866     {
00867       return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
00868     }
00870   any* get_optional_extra_data(
00871     const std::string& type_name, const std::string& name
00872     )
00873     {
00874       debug_assert_not_null();
00875       return node_->get_optional_extra_data(type_name, name);
00876     } 
00878   const any* get_optional_extra_data(
00879     const std::string& type_name, const std::string& name
00880     ) const
00881     {
00882       return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
00883     }
00885   void debug_assert_not_null() const
00886     {
00887 #ifdef TEUCHOS_DEBUG
00888       if (!node_)
00889         throw_null_ptr_error(typeName(*this));
00890 #endif
00891     }
00893   template<class RCPType>
00894   void assert_valid_ptr(const RCPType& rcp_obj) const
00895     {
00896       if (!node_)
00897         return; // Null is a valid pointer!
00898       if (!is_valid_ptr()) {
00899         node_->throw_invalid_obj_exception( typeName(rcp_obj),
00900           this, node_, rcp_obj.access_private_ptr() );
00901       }
00902     }
00904   template<class RCPType>
00905   void debug_assert_valid_ptr(const RCPType& rcp_obj) const
00906     {
00907 #ifdef TEUCHOS_DEBUG
00908       assert_valid_ptr(rcp_obj);
00909 #endif
00910     }
00911 #ifdef TEUCHOS_DEBUG
00912   const void* get_base_obj_map_key_void_ptr() const
00913     {
00914       if (node_)
00915         return node_->get_base_obj_map_key_void_ptr();
00916       return 0;
00917     }
00918 #endif
00919 private:
00920   RCPNode *node_;
00921   ERCPStrength strength_;
00922   inline void bind()
00923     {
00924       if (node_)
00925         node_->incr_count(strength_);
00926     }
00927   inline void unbind() 
00928     {
00929       // Optimize this implementation for count > 1
00930       if (node_ && node_->deincr_count(strength_)==0) {
00931         // If we get here, the reference count has gone to 0 and something
00932         // interesting is going to happen.  In this case, we need to
00933         // reincrement the count back to 1 and call the more complex function
00934         // that will either delete the object or delete the node.
00935         node_->incr_count(strength_);
00936         unbindOne();
00937       }
00938       // If we get here, either node_==0 or the count is still greater than 0.
00939       // In this case, nothing interesting is going to happen so we are done!
00940     }
00941   void unbindOne(); // Provides the "strong" guarantee!
00942 
00943 };
00944 
00945 
00950 inline
00951 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
00952 {
00953   return (out << node.node_ptr());
00954 }
00955 
00956 
00966 class TEUCHOS_LIB_DLL_EXPORT RCPNodeThrowDeleter {
00967 public:
00969   RCPNodeThrowDeleter(RCPNode *node)
00970     : node_(node)
00971     {}
00977   ~RCPNodeThrowDeleter()
00978     {
00979       if (node_) {
00980         node_->has_ownership(false); // Avoid actually deleting ptr_
00981         node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
00982         delete node_;
00983       }
00984     }
00986   RCPNode* get() const
00987     {
00988       return node_;
00989     }
00991   void release()
00992     {
00993       node_ = 0;
00994     }
00995 private:
00996   RCPNode *node_;
00997   RCPNodeThrowDeleter(); // Not defined
00998   RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
00999   RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
01000 };
01001 
01002 
01003 //
01004 // Unit testing support
01005 //
01006 
01007 
01008 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01009 
01010 class SetTracingActiveNodesStack {
01011 public: 
01012   SetTracingActiveNodesStack()
01013     {RCPNodeTracer::setTracingActiveRCPNodes(true);}
01014   ~SetTracingActiveNodesStack()
01015     {RCPNodeTracer::setTracingActiveRCPNodes(false);}
01016 };
01017 
01018 #  define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
01019 
01020 #else
01021 
01022 #  define SET_RCPNODE_TRACING() (void)0
01023 
01024 #endif //  defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01025 
01026 
01027 } // end namespace Teuchos
01028 
01029 
01030 #endif // TEUCHOS_RCP_NODE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Wed Apr 13 09:57:44 2011 for Teuchos - Trilinos Tools Package by  doxygen 1.6.3