|
Teuchos Package Browser (Single Doxygen Collection)
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 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00042 #ifndef TEUCHOS_RCP_NODE_HPP 00043 #define TEUCHOS_RCP_NODE_HPP 00044 00045 00052 #include "Teuchos_ConfigDefs.hpp" 00053 #include "Teuchos_any.hpp" 00054 #include "Teuchos_map.hpp" 00055 #include "Teuchos_ENull.hpp" 00056 #include "Teuchos_Assert.hpp" 00057 #include "Teuchos_Exceptions.hpp" 00058 #include "Teuchos_TypeNameTraits.hpp" 00059 #include "Teuchos_toString.hpp" 00060 #include "Teuchos_getBaseObjVoidPtr.hpp" 00061 00062 00063 namespace Teuchos { 00064 00065 00070 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY }; 00071 00076 enum ERCPStrength { RCP_STRENGTH_INVALID=-1, RCP_STRONG=0, RCP_WEAK=1 }; 00077 00082 enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP }; 00083 00085 inline void debugAssertStrength(ERCPStrength strength) 00086 { 00087 #ifdef TEUCHOS_DEBUG 00088 switch (strength) { 00089 case RCP_STRONG: 00090 // fall through 00091 case RCP_WEAK: 00092 return; // Fine 00093 case RCP_STRENGTH_INVALID: 00094 default: 00095 TEUCHOS_TEST_FOR_EXCEPT(true); 00096 } 00097 #endif 00098 } 00099 00105 template<> 00106 class TEUCHOS_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> { 00107 public: 00108 static std::string toString( const ERCPStrength &t ) 00109 { 00110 switch (t) { 00111 case RCP_STRENGTH_INVALID: 00112 return "RCP_STRENGTH_INVALID"; 00113 case RCP_STRONG: 00114 return "RCP_STRONG"; 00115 case RCP_WEAK: 00116 return "RCP_WEAK"; 00117 default: 00118 // Should never get here but fall through ... 00119 break; 00120 } 00121 // Should never get here! 00122 #ifdef TEUCHOS_DEBUG 00123 TEUCHOS_TEST_FOR_EXCEPT(true); 00124 #endif 00125 return ""; 00126 // 2009/06/30: rabartl: The above logic avoid a warning from the Intel 00127 // 10.1 compiler (remark #111) about the statement being unreachable. 00128 } 00129 }; 00130 00131 00143 class TEUCHOS_LIB_DLL_EXPORT RCPNode { 00144 public: 00146 RCPNode(bool has_ownership_in) 00147 : has_ownership_(has_ownership_in), extra_data_map_(NULL) 00148 #ifdef TEUCHOS_DEBUG 00149 ,insertion_number_(-1) 00150 #endif // TEUCHOS_DEBUG 00151 { 00152 count_[RCP_STRONG] = 0; 00153 count_[RCP_WEAK] = 0; 00154 } 00156 virtual ~RCPNode() 00157 { 00158 if(extra_data_map_) 00159 delete extra_data_map_; 00160 } 00162 int strong_count() const 00163 { 00164 return count_[RCP_STRONG]; 00165 } 00167 int weak_count() const 00168 { 00169 return count_[RCP_WEAK]; 00170 } 00172 int incr_count( const ERCPStrength strength ) 00173 { 00174 debugAssertStrength(strength); 00175 return ++count_[strength]; 00176 } 00178 int deincr_count( const ERCPStrength strength ) 00179 { 00180 debugAssertStrength(strength); 00181 return --count_[strength]; 00182 } 00184 void has_ownership(bool has_ownership_in) 00185 { 00186 has_ownership_ = has_ownership_in; 00187 } 00189 bool has_ownership() const 00190 { 00191 return has_ownership_; 00192 } 00194 void set_extra_data( 00195 const any &extra_data, const std::string& name, 00196 EPrePostDestruction destroy_when, bool force_unique ); 00198 any& get_extra_data( const std::string& type_name, 00199 const std::string& name ); 00201 const any& get_extra_data( const std::string& type_name, 00202 const std::string& name 00203 ) const 00204 { 00205 return const_cast<RCPNode*>(this)->get_extra_data(type_name, name); 00206 } 00208 any* get_optional_extra_data(const std::string& type_name, 00209 const std::string& name ); 00211 const any* get_optional_extra_data( 00212 const std::string& type_name, const std::string& name 00213 ) const 00214 { 00215 return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name); 00216 } 00218 virtual bool is_valid_ptr() const = 0; 00220 virtual void delete_obj() = 0; 00222 virtual void throw_invalid_obj_exception( 00223 const std::string& rcp_type_name, 00224 const void* rcp_ptr, 00225 const RCPNode* rcp_node_ptr, 00226 const void* rcp_obj_ptr 00227 ) const = 0; 00229 virtual const std::string get_base_obj_type_name() const = 0; 00230 #ifdef TEUCHOS_DEBUG 00231 00232 virtual const void* get_base_obj_map_key_void_ptr() const = 0; 00233 #endif 00234 protected: 00236 void pre_delete_extra_data() 00237 { 00238 if(extra_data_map_) 00239 impl_pre_delete_extra_data(); 00240 } 00241 private: 00242 struct extra_data_entry_t { 00243 extra_data_entry_t() : destroy_when(POST_DESTROY) {} 00244 extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when ) 00245 : extra_data(_extra_data), destroy_when(_destroy_when) 00246 {} 00247 any extra_data; 00248 EPrePostDestruction destroy_when; 00249 }; 00250 typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t; 00251 int count_[2]; 00252 bool has_ownership_; 00253 extra_data_map_t *extra_data_map_; 00254 // Above is made a pointer to reduce overhead for the general case when this 00255 // is not used. However, this adds just a little bit to the overhead when 00256 // it is used. 00257 // Provides the "basic" guarantee! 00258 void impl_pre_delete_extra_data(); 00259 // Not defined and not to be called 00260 RCPNode(); 00261 RCPNode(const RCPNode&); 00262 RCPNode& operator=(const RCPNode&); 00263 #ifdef TEUCHOS_DEBUG 00264 int insertion_number_; 00265 public: 00266 void set_insertion_number(int insertion_number_in) 00267 { 00268 insertion_number_ = insertion_number_in; 00269 } 00270 int insertion_number() const 00271 { 00272 return insertion_number_; 00273 } 00274 #endif // TEUCHOS_DEBUG 00275 }; 00276 00277 00282 TEUCHOS_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name ); 00283 00284 00301 class TEUCHOS_LIB_DLL_EXPORT RCPNodeTracer { 00302 public: 00303 00306 00308 struct RCPNodeStatistics { 00309 RCPNodeStatistics() 00310 : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0), 00311 totalNumRCPNodeDeletions(0) 00312 {} 00313 long int maxNumRCPNodes; 00314 long int totalNumRCPNodeAllocations; 00315 long int totalNumRCPNodeDeletions; 00316 }; 00317 00319 00322 00328 static bool isTracingActiveRCPNodes(); 00329 00330 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 00331 00348 static void setTracingActiveRCPNodes(bool tracingActiveNodes); 00349 #endif 00350 00354 static int numActiveRCPNodes(); 00355 00357 static RCPNodeStatistics getRCPNodeStatistics() ; 00358 00360 static void printRCPNodeStatistics( 00361 const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out); 00362 00366 static void setPrintRCPNodeStatisticsOnExit( 00367 bool printRCPNodeStatisticsOnExit); 00368 00372 static bool getPrintRCPNodeStatisticsOnExit(); 00373 00388 static void printActiveRCPNodes(std::ostream &out); 00389 00391 00396 00401 static void addNewRCPNode(RCPNode* rcp_node, 00402 const std::string &info ); 00403 00409 static void removeRCPNode( RCPNode* rcp_node ); 00410 00419 template<class T> 00420 static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p) 00421 { 00422 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR 00423 return getBaseObjVoidPtr(p); 00424 #else 00425 // This will not return the base address for polymorphic types if 00426 // multiple inheritance and/or virtual bases are used but returning the 00427 // static_cast should be okay in how it is used. It is just that the 00428 // RCPNode tracing support will not always be able to figure out if two 00429 // pointers of different type are pointing to the same object or not. 00430 return static_cast<const void*>(p); 00431 #endif 00432 } 00433 00440 static RCPNode* getExistingRCPNodeGivenLookupKey( 00441 const void* lookupKey); 00442 00449 template<class T> 00450 static RCPNode* getExistingRCPNode(T *p) 00451 { 00452 return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p)); 00453 } 00454 00456 static std::string getActiveRCPNodeHeaderString(); 00457 00459 static std::string getCommonDebugNotesString(); 00460 00462 00463 }; 00464 00465 00466 #ifdef TEUCHOS_DEBUG 00467 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \ 00468 " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n" 00469 #else 00470 # define TEUCHOS_RCP_INSERION_NUMBER_STR() 00471 #endif 00472 00473 00479 template<class T, class Dealloc_T> 00480 class RCPNodeTmpl : public RCPNode { 00481 public: 00483 RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in) 00484 : RCPNode(has_ownership_in), ptr_(p), 00485 #ifdef TEUCHOS_DEBUG 00486 base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)), 00487 deleted_ptr_(0), 00488 #endif 00489 dealloc_(dealloc) 00490 {} 00492 RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull) 00493 : RCPNode(has_ownership_in), ptr_(p), 00494 #ifdef TEUCHOS_DEBUG 00495 base_obj_map_key_void_ptr_(0), 00496 deleted_ptr_(0), 00497 #endif 00498 dealloc_(dealloc) 00499 {} 00501 Dealloc_T& get_nonconst_dealloc() 00502 { return dealloc_; } 00504 const Dealloc_T& get_dealloc() const 00505 { return dealloc_; } 00507 ~RCPNodeTmpl() 00508 { 00509 #ifdef TEUCHOS_DEBUG 00510 TEUCHOS_TEST_FOR_EXCEPTION( ptr_!=0, std::logic_error, 00511 "Error, the underlying object must be explicitly deleted before deleting" 00512 " the node object!" ); 00513 #endif 00514 } 00516 virtual bool is_valid_ptr() const 00517 { 00518 return ptr_ != 0; 00519 } 00525 virtual void delete_obj() 00526 { 00527 if (ptr_!= 0) { 00528 this->pre_delete_extra_data(); // May throw! 00529 T* tmp_ptr = ptr_; 00530 #ifdef TEUCHOS_DEBUG 00531 deleted_ptr_ = tmp_ptr; 00532 #endif 00533 ptr_ = 0; 00534 if (has_ownership()) { 00535 #ifdef TEUCHOS_DEBUG 00536 try { 00537 #endif 00538 dealloc_.free(tmp_ptr); 00539 #ifdef TEUCHOS_DEBUG 00540 } 00541 catch(...) { 00542 // Object was not deleted due to an exception! 00543 ptr_ = tmp_ptr; 00544 throw; 00545 } 00546 #endif 00547 } 00548 // 2008/09/22: rabartl: Above, we have to be careful to set the member 00549 // this->ptr_=0 before calling delete on the object's address in order 00550 // to avoid a double call to delete in cases of circular references 00551 // involving weak and strong pointers (see the unit test 00552 // circularReference_c_then_a in RCP_UnitTests.cpp). NOTE: It is 00553 // critcial that no member of *this get accesses after 00554 // dealloc_.free(...) gets called! Also, in order to provide the 00555 // "strong" guarantee we have to include the above try/catch. This 00556 // overhead is unfortunate but I don't know of any other way to 00557 // statisfy the "strong" guarantee and still avoid a double delete. 00558 } 00559 } 00561 virtual void throw_invalid_obj_exception( 00562 const std::string& rcp_type_name, 00563 const void* rcp_ptr, 00564 const RCPNode* rcp_node_ptr, 00565 const void* rcp_obj_ptr 00566 ) const 00567 { 00568 TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" ); 00569 const T* deleted_ptr = 00570 #ifdef TEUCHOS_DEBUG 00571 deleted_ptr_ 00572 #else 00573 0 00574 #endif 00575 ; 00576 TEUCHOS_ASSERT(rcp_node_ptr); 00577 TEUCHOS_TEST_FOR_EXCEPTION( true, DanglingReferenceError, 00578 "Error, an attempt has been made to dereference the underlying object\n" 00579 "from a weak smart pointer object where the underling object has already\n" 00580 "been deleted since the strong count has already gone to zero.\n" 00581 "\n" 00582 "Context information:\n" 00583 "\n" 00584 " RCP type: " << rcp_type_name << "\n" 00585 " RCP address: " << rcp_ptr << "\n" 00586 " RCPNode type: " << typeName(*this) << "\n" 00587 " RCPNode address: " << rcp_node_ptr << "\n" 00588 TEUCHOS_RCP_INSERION_NUMBER_STR() 00589 " RCP ptr address: " << rcp_obj_ptr << "\n" 00590 " Concrete ptr address: " << deleted_ptr << "\n" 00591 "\n" 00592 << RCPNodeTracer::getCommonDebugNotesString() 00593 ); 00594 // 2008/09/22: rabartl: Above, we do not provide the concreate object 00595 // type or the concrete object address. In the case of the concrete 00596 // object address, in a non-debug build, we don't want to pay a price 00597 // for extra storage that we strictly don't need. In the case of the 00598 // concrete object type name, we don't want to force non-debug built 00599 // code to have the require that types be fully defined in order to use 00600 // the memory management software. This is related to bug 4016. 00601 00602 } 00604 const std::string get_base_obj_type_name() const 00605 { 00606 #ifdef TEUCHOS_DEBUG 00607 return TypeNameTraits<T>::name(); 00608 #else 00609 return "UnknownType"; 00610 #endif 00611 } 00612 #ifdef TEUCHOS_DEBUG 00613 00614 const void* get_base_obj_map_key_void_ptr() const 00615 { 00616 return base_obj_map_key_void_ptr_; 00617 } 00618 #endif 00619 private: 00620 T *ptr_; 00621 #ifdef TEUCHOS_DEBUG 00622 const void *base_obj_map_key_void_ptr_; 00623 T *deleted_ptr_; 00624 #endif 00625 Dealloc_T dealloc_; 00626 // not defined and not to be called 00627 RCPNodeTmpl(); 00628 RCPNodeTmpl(const RCPNodeTmpl&); 00629 RCPNodeTmpl& operator=(const RCPNodeTmpl&); 00630 00631 }; // end class RCPNodeTmpl<T> 00632 00633 00641 class TEUCHOS_LIB_DLL_EXPORT ActiveRCPNodesSetup { 00642 public: 00644 ActiveRCPNodesSetup(); 00646 ~ActiveRCPNodesSetup(); 00648 void foo(); 00649 private: 00650 static int count_; 00651 }; 00652 00653 00654 } // namespace Teuchos 00655 00656 00657 namespace { 00658 // This static variable is delcared before all other static variables that 00659 // depend on RCP or other classes. Therefore, this static varaible will be 00660 // deleted *after* all of these other static variables that depend on RCP or 00661 // created classes go away! This ensures that the node tracing machinery is 00662 // setup and torn down correctly (this is the same trick used by the standard 00663 // stream objects in many compiler implementations). 00664 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup; 00665 } // namespace 00666 00667 00668 namespace Teuchos { 00669 00670 00686 class TEUCHOS_LIB_DLL_EXPORT RCPNodeHandle { 00687 public: 00689 RCPNodeHandle(ENull null_arg = null) 00690 : node_(0), strength_(RCP_STRENGTH_INVALID) 00691 {(void)null_arg;} 00693 RCPNodeHandle( RCPNode* node, ERCPStrength strength_in = RCP_STRONG, 00694 bool newNode = true 00695 ) 00696 : node_(node), strength_(strength_in) 00697 { 00698 #ifdef TEUCHOS_DEBUG 00699 TEUCHOS_ASSERT(node); 00700 #endif 00701 bind(); 00702 #ifdef TEUCHOS_DEBUG 00703 // Add the node if this is the first RCPNodeHandle to get it. We have 00704 // to add it because unbind() will call the remove_RCPNode(...) function 00705 // and it needs to match when node tracing is on from the beginning. 00706 if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) 00707 { 00708 std::ostringstream os; 00709 os << "{T=Unknown, ConcreteT=Unknown, p=Unknown," 00710 << " has_ownership="<<node_->has_ownership()<<"}"; 00711 RCPNodeTracer::addNewRCPNode(node_, os.str()); 00712 } 00713 #endif 00714 } 00715 #ifdef TEUCHOS_DEBUG 00716 00717 template<typename T> 00718 RCPNodeHandle(RCPNode* node, T *p, const std::string &T_name, 00719 const std::string &ConcreteT_name, const bool has_ownership_in, 00720 ERCPStrength strength_in = RCP_STRONG 00721 ) 00722 : node_(node), strength_(strength_in) 00723 { 00724 TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet! 00725 TEUCHOS_ASSERT(node_); 00726 bind(); 00727 if (RCPNodeTracer::isTracingActiveRCPNodes()) { 00728 std::ostringstream os; 00729 os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name 00730 <<", p="<<static_cast<const void*>(p) 00731 <<", has_ownership="<<has_ownership_in<<"}"; 00732 RCPNodeTracer::addNewRCPNode(node_, os.str()); 00733 } 00734 } 00735 #endif // TEUCHOS_DEBUG 00736 00737 RCPNodeHandle(const RCPNodeHandle& node_ref) 00738 : node_(node_ref.node_), strength_(node_ref.strength_) 00739 { 00740 bind(); 00741 } 00743 void swap( RCPNodeHandle& node_ref ) 00744 { 00745 std::swap(node_ref.node_, node_); 00746 std::swap(node_ref.strength_, strength_); 00747 } 00749 RCPNodeHandle& operator=(const RCPNodeHandle& node_ref) 00750 { 00751 // Assignment to self check: Note, We don't need to do an assigment to 00752 // self check here because such a check is already done in the RCP and 00753 // ArrayRCP classes. 00754 // Take care of this's existing node and object 00755 unbind(); // May throw in some cases 00756 // Assign the new node 00757 node_ = node_ref.node_; 00758 strength_ = node_ref.strength_; 00759 bind(); 00760 // Return 00761 return *this; 00762 } 00764 ~RCPNodeHandle() 00765 { 00766 unbind(); 00767 } 00769 RCPNodeHandle create_weak() const 00770 { 00771 if (node_) { 00772 return RCPNodeHandle(node_, RCP_WEAK, false); 00773 } 00774 return RCPNodeHandle(); 00775 } 00777 RCPNodeHandle create_strong() const 00778 { 00779 if (node_) { 00780 return RCPNodeHandle(node_, RCP_STRONG, false); 00781 } 00782 return RCPNodeHandle(); 00783 } 00785 RCPNode* node_ptr() const 00786 { 00787 return node_; 00788 } 00790 bool is_node_null() const 00791 { 00792 return node_==0; 00793 } 00795 bool is_valid_ptr() const 00796 { 00797 if (node_) 00798 return node_->is_valid_ptr(); 00799 return true; // Null is a valid ptr! 00800 } 00802 bool same_node(const RCPNodeHandle &node2) const 00803 { 00804 return node_ == node2.node_; 00805 } 00807 int strong_count() const 00808 { 00809 if (node_) 00810 return node_->strong_count(); 00811 return 0; 00812 } 00814 int weak_count() const 00815 { 00816 if (node_) 00817 return node_->weak_count(); 00818 return 0; 00819 } 00821 int total_count() const 00822 { 00823 if (node_) 00824 return node_->strong_count() + node_->weak_count(); 00825 return 0; 00826 } 00828 int count() const 00829 { 00830 if (node_) 00831 return node_->strong_count(); 00832 return 0; 00833 } 00835 ERCPStrength strength() const 00836 { 00837 return strength_; 00838 } 00840 void has_ownership(bool has_ownership_in) 00841 { 00842 if (node_) 00843 node_->has_ownership(has_ownership_in); 00844 } 00846 bool has_ownership() const 00847 { 00848 if (node_) 00849 return node_->has_ownership(); 00850 return false; 00851 } 00853 void set_extra_data( 00854 const any &extra_data, const std::string& name, 00855 EPrePostDestruction destroy_when, bool force_unique 00856 ) 00857 { 00858 debug_assert_not_null(); 00859 node_->set_extra_data(extra_data, name, destroy_when, force_unique); 00860 } 00862 any& get_extra_data( const std::string& type_name, 00863 const std::string& name 00864 ) 00865 { 00866 debug_assert_not_null(); 00867 return node_->get_extra_data(type_name, name); 00868 } 00870 const any& get_extra_data( const std::string& type_name, 00871 const std::string& name 00872 ) const 00873 { 00874 return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name); 00875 } 00877 any* get_optional_extra_data( 00878 const std::string& type_name, const std::string& name 00879 ) 00880 { 00881 debug_assert_not_null(); 00882 return node_->get_optional_extra_data(type_name, name); 00883 } 00885 const any* get_optional_extra_data( 00886 const std::string& type_name, const std::string& name 00887 ) const 00888 { 00889 return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name); 00890 } 00892 void debug_assert_not_null() const 00893 { 00894 #ifdef TEUCHOS_DEBUG 00895 if (!node_) 00896 throw_null_ptr_error(typeName(*this)); 00897 #endif 00898 } 00900 template<class RCPType> 00901 void assert_valid_ptr(const RCPType& rcp_obj) const 00902 { 00903 if (!node_) 00904 return; // Null is a valid pointer! 00905 if (!is_valid_ptr()) { 00906 node_->throw_invalid_obj_exception( typeName(rcp_obj), 00907 this, node_, rcp_obj.access_private_ptr() ); 00908 } 00909 } 00911 template<class RCPType> 00912 void debug_assert_valid_ptr(const RCPType& rcp_obj) const 00913 { 00914 #ifdef TEUCHOS_DEBUG 00915 assert_valid_ptr(rcp_obj); 00916 #endif 00917 } 00918 #ifdef TEUCHOS_DEBUG 00919 const void* get_base_obj_map_key_void_ptr() const 00920 { 00921 if (node_) 00922 return node_->get_base_obj_map_key_void_ptr(); 00923 return 0; 00924 } 00925 #endif 00926 private: 00927 RCPNode *node_; 00928 ERCPStrength strength_; 00929 inline void bind() 00930 { 00931 if (node_) 00932 node_->incr_count(strength_); 00933 } 00934 inline void unbind() 00935 { 00936 // Optimize this implementation for count > 1 00937 if (node_ && node_->deincr_count(strength_)==0) { 00938 // If we get here, the reference count has gone to 0 and something 00939 // interesting is going to happen. In this case, we need to 00940 // reincrement the count back to 1 and call the more complex function 00941 // that will either delete the object or delete the node. 00942 node_->incr_count(strength_); 00943 unbindOne(); 00944 } 00945 // If we get here, either node_==0 or the count is still greater than 0. 00946 // In this case, nothing interesting is going to happen so we are done! 00947 } 00948 void unbindOne(); // Provides the "strong" guarantee! 00949 00950 }; 00951 00952 00957 inline 00958 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node) 00959 { 00960 return (out << node.node_ptr()); 00961 } 00962 00963 00973 class TEUCHOS_LIB_DLL_EXPORT RCPNodeThrowDeleter { 00974 public: 00976 RCPNodeThrowDeleter(RCPNode *node) 00977 : node_(node) 00978 {} 00984 ~RCPNodeThrowDeleter() 00985 { 00986 if (node_) { 00987 node_->has_ownership(false); // Avoid actually deleting ptr_ 00988 node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete 00989 delete node_; 00990 } 00991 } 00993 RCPNode* get() const 00994 { 00995 return node_; 00996 } 00998 void release() 00999 { 01000 node_ = 0; 01001 } 01002 private: 01003 RCPNode *node_; 01004 RCPNodeThrowDeleter(); // Not defined 01005 RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined 01006 RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined 01007 }; 01008 01009 01010 // 01011 // Unit testing support 01012 // 01013 01014 01015 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 01016 01017 class SetTracingActiveNodesStack { 01018 public: 01019 SetTracingActiveNodesStack() 01020 {RCPNodeTracer::setTracingActiveRCPNodes(true);} 01021 ~SetTracingActiveNodesStack() 01022 {RCPNodeTracer::setTracingActiveRCPNodes(false);} 01023 }; 01024 01025 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack; 01026 01027 #else 01028 01029 # define SET_RCPNODE_TRACING() (void)0 01030 01031 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 01032 01033 01034 } // end namespace Teuchos 01035 01036 01037 #endif // TEUCHOS_RCP_NODE_HPP
1.7.6.1