00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
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
00064
00065
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
00082 break;
00083 }
00084
00085 #ifdef TEUCHOS_DEBUG
00086 TEST_FOR_EXCEPT(true);
00087 #endif
00088 return "";
00089
00090
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;
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;
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
00222
00223
00224
00225 void impl_pre_delete_extra_data();
00226
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();
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
00291 ptr_ = tmp_ptr;
00292 throw;
00293 }
00294 #endif
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
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
00346
00347
00348
00349
00350
00351
00352
00353 }
00354 private:
00355 T *ptr_;
00356 #ifdef TEUCHOS_DEBUG
00357 T *deleted_ptr_;
00358 #endif
00359 Dealloc_T dealloc_;
00360
00361 RCPNodeTmpl();
00362 RCPNodeTmpl(const RCPNodeTmpl&);
00363 RCPNodeTmpl& operator=(const RCPNodeTmpl&);
00364
00365 };
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 }
00457
00458
00459 namespace {
00460
00461
00462
00463
00464 Teuchos::PrintActiveRCPNodes local_printActiveRCPNodes;
00465 }
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);
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
00524 if ( this == &node_ref )
00525 return *this;
00526
00527 unbind();
00528
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;
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;
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
00696 void unbind()
00697 {
00698 if (node_) {
00699
00700
00701
00702 if (node_->strong_count()==1 && strength()==RCP_STRONG) {
00703
00704 node_->delete_obj();
00705 }
00706
00707 if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
00708
00709
00710 #ifdef TEUCHOS_DEBUG
00711 local_printActiveRCPNodes.foo();
00712 remove_RCPNode(node_);
00713 #endif
00714 delete node_;
00715 node_ = 0;
00716
00717
00718 }
00719 else {
00720
00721
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 }
00742
00743
00744 #endif // TEUCHOS_RCP_NODE_HPP