|
Teuchos - Trilinos Tools Package Version of the Day
|
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
1.7.4