Teuchos Package Browser (Single Doxygen Collection) Version of the Day
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 // 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_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   default:
00094     TEUCHOS_TEST_FOR_EXCEPTION(
00095       true, std::logic_error, "Teuchos::RCPNode: ERCPStrength enum value "
00096       << strength << " is invalid (neither RCP_STRONG = " << RCP_STRONG
00097       << " nor RCP_WEAK = " << RCP_WEAK << ").");
00098   }
00099 #else
00100   (void) strength; // Silence "unused variable" compiler warning.
00101 #endif // TEUCHOS_DEBUG
00102 }
00103 
00109 template<>
00110 class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
00111 public:
00112   static std::string toString( const ERCPStrength &t )
00113     {
00114       switch (t) {
00115         case RCP_STRONG:
00116           return "RCP_STRONG";
00117         case RCP_WEAK:
00118           return "RCP_WEAK";
00119         default:
00120           // Should never get here but fall through ...
00121           break;
00122       }
00123       // Should never get here!
00124 #ifdef TEUCHOS_DEBUG
00125       TEUCHOS_TEST_FOR_EXCEPT(true);
00126 #endif
00127       return "";
00128       // 2009/06/30: rabartl: The above logic avoid a warning from the Intel
00129       // 10.1 compiler (remark #111) about the statement being unreachable.
00130       //
00131       // mfh (06 Mar 2013) This triggers a warning in Clang 3.2 with
00132       // "-Weverything", because it's an unreachable statement.  Alas,
00133       // we can't please _all_ the compilers equally...
00134     }
00135 };
00136 
00137 
00149 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
00150 public:
00152   RCPNode(bool has_ownership_in)
00153     : has_ownership_(has_ownership_in), extra_data_map_(NULL)
00154 #ifdef TEUCHOS_DEBUG
00155     ,insertion_number_(-1)
00156 #endif // TEUCHOS_DEBUG
00157     {
00158       count_[RCP_STRONG] = 0;
00159       count_[RCP_WEAK] = 0;
00160     }
00162   virtual ~RCPNode()
00163     {
00164       if(extra_data_map_)
00165         delete extra_data_map_;
00166     }
00168   int strong_count() const
00169     {
00170       return count_[RCP_STRONG];
00171     }
00173   int weak_count() const
00174     {
00175       return count_[RCP_WEAK];
00176     }
00178   int incr_count( const ERCPStrength strength )
00179     {
00180       debugAssertStrength(strength);
00181       return ++count_[strength];
00182     }
00184   int deincr_count( const ERCPStrength strength )
00185     {
00186       debugAssertStrength(strength);
00187       return --count_[strength];
00188     }
00190   void has_ownership(bool has_ownership_in)
00191     {
00192       has_ownership_ = has_ownership_in;
00193     }
00195   bool has_ownership() const
00196     {
00197       return has_ownership_;
00198     }
00200   void set_extra_data(
00201     const any &extra_data, const std::string& name,
00202     EPrePostDestruction destroy_when, bool force_unique );
00204   any& get_extra_data( const std::string& type_name,
00205     const std::string& name );
00207   const any& get_extra_data( const std::string& type_name,
00208     const std::string& name
00209     ) const
00210     {
00211       return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
00212     }
00214   any* get_optional_extra_data(const std::string& type_name,
00215     const std::string& name );
00217   const any* get_optional_extra_data(
00218     const std::string& type_name, const std::string& name
00219     ) const
00220     {
00221       return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
00222     }
00224   virtual bool is_valid_ptr() const = 0;
00226   virtual void delete_obj() = 0;
00228   virtual void throw_invalid_obj_exception(
00229     const std::string& rcp_type_name,
00230     const void* rcp_ptr,
00231     const RCPNode* rcp_node_ptr,
00232     const void* rcp_obj_ptr
00233     ) const = 0;
00235   virtual const std::string get_base_obj_type_name() const = 0;
00236 #ifdef TEUCHOS_DEBUG
00237 
00238   virtual const void* get_base_obj_map_key_void_ptr() const = 0;
00239 #endif
00240 protected:
00242   void pre_delete_extra_data()
00243     {
00244       if(extra_data_map_)
00245         impl_pre_delete_extra_data();
00246     }
00247 private:
00248   struct extra_data_entry_t {
00249     extra_data_entry_t() : destroy_when(POST_DESTROY) {}
00250     extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
00251       : extra_data(_extra_data), destroy_when(_destroy_when)
00252       {}
00253     any extra_data;
00254     EPrePostDestruction destroy_when;
00255   };
00256   typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
00257   int count_[2];
00258   bool has_ownership_;
00259   extra_data_map_t *extra_data_map_;
00260   // Above is made a pointer to reduce overhead for the general case when this
00261   // is not used.  However, this adds just a little bit to the overhead when
00262   // it is used.
00263   // Provides the "basic" guarantee!
00264   void impl_pre_delete_extra_data();
00265   // Not defined and not to be called
00266   RCPNode();
00267   RCPNode(const RCPNode&);
00268   RCPNode& operator=(const RCPNode&);
00269 #ifdef TEUCHOS_DEBUG
00270   int insertion_number_;
00271 public:
00272   void set_insertion_number(int insertion_number_in)
00273     {
00274       insertion_number_ = insertion_number_in;
00275     }
00276   int insertion_number() const
00277     {
00278       return insertion_number_;
00279     }
00280 #endif // TEUCHOS_DEBUG
00281 };
00282 
00283 
00288 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
00289 
00290 
00307 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
00308 public:
00309 
00312 
00314   struct RCPNodeStatistics {
00315     RCPNodeStatistics()
00316       : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
00317         totalNumRCPNodeDeletions(0)
00318       {}
00319     long int maxNumRCPNodes;
00320     long int totalNumRCPNodeAllocations;
00321     long int totalNumRCPNodeDeletions;
00322   };
00323 
00325 
00328 
00334   static bool isTracingActiveRCPNodes();
00335 
00336 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00337 
00354   static void setTracingActiveRCPNodes(bool tracingActiveNodes);
00355 #endif
00356 
00360   static int numActiveRCPNodes();
00361 
00363   static RCPNodeStatistics getRCPNodeStatistics() ;
00364 
00366   static void printRCPNodeStatistics(
00367     const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
00368 
00372   static void setPrintRCPNodeStatisticsOnExit(
00373     bool printRCPNodeStatisticsOnExit);
00374 
00378   static bool getPrintRCPNodeStatisticsOnExit();
00379 
00394   static void printActiveRCPNodes(std::ostream &out);
00395 
00397 
00402 
00407   static void addNewRCPNode(RCPNode* rcp_node,
00408     const std::string &info );
00409 
00415   static void removeRCPNode( RCPNode* rcp_node );
00416 
00425   template<class T>
00426   static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
00427     {
00428 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
00429       return getBaseObjVoidPtr(p);
00430 #else
00431       // This will not return the base address for polymorphic types if
00432       // multiple inheritance and/or virtual bases are used but returning the
00433       // static_cast should be okay in how it is used.  It is just that the
00434       // RCPNode tracing support will not always be able to figure out if two
00435       // pointers of different type are pointing to the same object or not.
00436       return static_cast<const void*>(p);
00437 #endif
00438     }
00439 
00446   static RCPNode* getExistingRCPNodeGivenLookupKey(
00447     const void* lookupKey);
00448 
00455   template<class T>
00456   static RCPNode* getExistingRCPNode(T *p)
00457     {
00458       return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
00459     }
00460 
00462   static std::string getActiveRCPNodeHeaderString();
00463 
00465   static std::string getCommonDebugNotesString();
00466 
00468 
00469 };
00470 
00471 
00472 #ifdef TEUCHOS_DEBUG
00473 #  define TEUCHOS_RCP_INSERION_NUMBER_STR() \
00474       "  insertionNumber:      " << rcp_node_ptr->insertion_number() << "\n"
00475 #else
00476 #  define TEUCHOS_RCP_INSERION_NUMBER_STR()
00477 #endif
00478 
00479 
00485 template<class T, class Dealloc_T>
00486 class RCPNodeTmpl : public RCPNode {
00487 public:
00489   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
00490     : RCPNode(has_ownership_in), ptr_(p),
00491 #ifdef TEUCHOS_DEBUG
00492       base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
00493       deleted_ptr_(0),
00494 #endif
00495       dealloc_(dealloc)
00496     {}
00498   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
00499     : RCPNode(has_ownership_in), ptr_(p),
00500 #ifdef TEUCHOS_DEBUG
00501       base_obj_map_key_void_ptr_(0),
00502       deleted_ptr_(0),
00503 #endif
00504       dealloc_(dealloc)
00505     {}
00507   Dealloc_T& get_nonconst_dealloc()
00508     { return dealloc_; }
00510   const Dealloc_T& get_dealloc() const
00511     { return dealloc_; }
00513   ~RCPNodeTmpl()
00514     {
00515 #ifdef TEUCHOS_DEBUG
00516       TEUCHOS_TEST_FOR_EXCEPTION( ptr_!=0, std::logic_error,
00517         "Error, the underlying object must be explicitly deleted before deleting"
00518         " the node object!" );
00519 #endif
00520     }
00522   virtual bool is_valid_ptr() const
00523     {
00524       return ptr_ != 0;
00525     }
00531   virtual void delete_obj()
00532     {
00533       if (ptr_!= 0) {
00534         this->pre_delete_extra_data(); // May throw!
00535         T* tmp_ptr = ptr_;
00536 #ifdef TEUCHOS_DEBUG
00537         deleted_ptr_ = tmp_ptr;
00538 #endif
00539         ptr_ = 0;
00540         if (has_ownership()) {
00541 #ifdef TEUCHOS_DEBUG
00542           try {
00543 #endif
00544             dealloc_.free(tmp_ptr);
00545 #ifdef TEUCHOS_DEBUG
00546           }
00547           catch(...) {
00548             // Object was not deleted due to an exception!
00549             ptr_ = tmp_ptr;
00550             throw;
00551           }
00552 #endif
00553         }
00554         // 2008/09/22: rabartl: Above, we have to be careful to set the member
00555         // this->ptr_=0 before calling delete on the object's address in order
00556         // to avoid a double call to delete in cases of circular references
00557         // involving weak and strong pointers (see the unit test
00558         // circularReference_c_then_a in RCP_UnitTests.cpp).  NOTE: It is
00559         // critcial that no member of *this get accesses after
00560         // dealloc_.free(...) gets called!  Also, in order to provide the
00561         // "strong" guarantee we have to include the above try/catch.  This
00562         // overhead is unfortunate but I don't know of any other way to
00563         // statisfy the "strong" guarantee and still avoid a double delete.
00564       }
00565     }
00567   virtual void throw_invalid_obj_exception(
00568     const std::string& rcp_type_name,
00569     const void* rcp_ptr,
00570     const RCPNode* rcp_node_ptr,
00571     const void* rcp_obj_ptr
00572     ) const
00573     {
00574       TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
00575       const T* deleted_ptr =
00576 #ifdef TEUCHOS_DEBUG
00577         deleted_ptr_
00578 #else
00579         0
00580 #endif
00581         ;
00582       TEUCHOS_ASSERT(rcp_node_ptr);
00583       TEUCHOS_TEST_FOR_EXCEPTION( true, DanglingReferenceError,
00584         "Error, an attempt has been made to dereference the underlying object\n"
00585         "from a weak smart pointer object where the underling object has already\n"
00586         "been deleted since the strong count has already gone to zero.\n"
00587         "\n"
00588         "Context information:\n"
00589         "\n"
00590         "  RCP type:             " << rcp_type_name << "\n"
00591         "  RCP address:          " << rcp_ptr << "\n"
00592         "  RCPNode type:         " << typeName(*this) << "\n"
00593         "  RCPNode address:      " << rcp_node_ptr << "\n"
00594         TEUCHOS_RCP_INSERION_NUMBER_STR()
00595         "  RCP ptr address:      " << rcp_obj_ptr << "\n"
00596         "  Concrete ptr address: " << deleted_ptr << "\n"
00597         "\n"
00598         << RCPNodeTracer::getCommonDebugNotesString()
00599         );
00600       // 2008/09/22: rabartl: Above, we do not provide the concreate object
00601       // type or the concrete object address.  In the case of the concrete
00602       // object address, in a non-debug build, we don't want to pay a price
00603       // for extra storage that we strictly don't need.  In the case of the
00604       // concrete object type name, we don't want to force non-debug built
00605       // code to have the require that types be fully defined in order to use
00606       // the memory management software.  This is related to bug 4016.
00607 
00608     }
00610   const std::string get_base_obj_type_name() const
00611     {
00612 #ifdef TEUCHOS_DEBUG
00613       return TypeNameTraits<T>::name();
00614 #else
00615       return "UnknownType";
00616 #endif
00617     }
00618 #ifdef TEUCHOS_DEBUG
00619 
00620   const void* get_base_obj_map_key_void_ptr() const
00621     {
00622       return base_obj_map_key_void_ptr_;
00623     }
00624 #endif
00625 private:
00626   T *ptr_;
00627 #ifdef TEUCHOS_DEBUG
00628   const void *base_obj_map_key_void_ptr_;
00629   T *deleted_ptr_;
00630 #endif
00631   Dealloc_T dealloc_;
00632   // not defined and not to be called
00633   RCPNodeTmpl();
00634   RCPNodeTmpl(const RCPNodeTmpl&);
00635   RCPNodeTmpl& operator=(const RCPNodeTmpl&);
00636 
00637 }; // end class RCPNodeTmpl<T>
00638 
00639 
00647 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
00648 public:
00650   ActiveRCPNodesSetup();
00652   ~ActiveRCPNodesSetup();
00654   void foo();
00655 private:
00656   static int count_;
00657 };
00658 
00659 
00660 } // namespace Teuchos
00661 
00662 
00663 namespace {
00664 // This static variable is declared before all other static variables that
00665 // depend on RCP or other classes. Therefore, this static variable will be
00666 // deleted *after* all of these other static variables that depend on RCP or
00667 // created classes go away!  This ensures that the node tracing machinery is
00668 // setup and torn down correctly (this is the same trick used by the standard
00669 // stream objects in many compiler implementations).
00670 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
00671 } // namespace (anonymous)
00672 
00673 
00674 namespace Teuchos {
00675 
00692 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
00693 public:
00695   RCPNodeHandle (ENull null_arg = null)
00696     : node_ (0), strength_ (RCP_STRONG)
00697   {
00698     (void) null_arg; // Silence "unused variable" compiler warning.
00699   }
00700 
00702   RCPNodeHandle (RCPNode* node,
00703                  ERCPStrength strength_in = RCP_STRONG,
00704                  bool newNode = true)
00705     : node_ (node), strength_ (strength_in)
00706   {
00707 #ifdef TEUCHOS_DEBUG
00708     TEUCHOS_ASSERT(node);
00709 #endif // TEUCHOS_DEBUG
00710 
00711     bind();
00712 
00713 #ifdef TEUCHOS_DEBUG
00714     // Add the node if this is the first RCPNodeHandle to get it.  We have
00715     // to add it because unbind() will call the remove_RCPNode(...) function
00716     // and it needs to match when node tracing is on from the beginning.
00717     if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) {
00718       std::ostringstream os;
00719       os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
00720          << " has_ownership="<<node_->has_ownership()<<"}";
00721       RCPNodeTracer::addNewRCPNode(node_, os.str());
00722     }
00723 #else
00724     (void) newNode; // Silence "unused variable" compiler warning.
00725 #endif // TEUCHOS_DEBUG
00726   }
00727 
00728 #ifdef TEUCHOS_DEBUG
00729 
00730   template<typename T>
00731   RCPNodeHandle (RCPNode* node, T *p, const std::string &T_name,
00732                  const std::string &ConcreteT_name,
00733                  const bool has_ownership_in,
00734                  ERCPStrength strength_in = RCP_STRONG)
00735     : node_ (node), strength_ (strength_in)
00736   {
00737     TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
00738     TEUCHOS_ASSERT(node_);
00739     bind();
00740     if (RCPNodeTracer::isTracingActiveRCPNodes()) {
00741       std::ostringstream os;
00742       os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
00743          <<", p="<<static_cast<const void*>(p)
00744          <<", has_ownership="<<has_ownership_in<<"}";
00745       RCPNodeTracer::addNewRCPNode(node_, os.str());
00746     }
00747   }
00748 #endif // TEUCHOS_DEBUG
00749 
00751   RCPNodeHandle (const RCPNodeHandle& node_ref)
00752     : node_ (node_ref.node_), strength_ (node_ref.strength_)
00753   {
00754     bind();
00755   }
00756 
00758   void swap (RCPNodeHandle& node_ref) {
00759     std::swap (node_ref.node_, node_);
00760     std::swap (node_ref.strength_, strength_);
00761   }
00762 
00768   RCPNodeHandle& operator= (const RCPNodeHandle& node_ref) {
00769     // Assignment to self check: Note, We don't need to do an assigment to
00770     // self check here because such a check is already done in the RCP and
00771     // ArrayRCP classes.
00772     // Take care of this's existing node and object
00773     unbind(); // May throw in some cases
00774     // Assign the new node
00775     node_ = node_ref.node_;
00776     strength_ = node_ref.strength_;
00777     bind();
00778     // Return
00779     return *this;
00780   }
00781 
00783   ~RCPNodeHandle() {
00784     unbind();
00785   }
00786 
00788   RCPNodeHandle create_weak() const {
00789     if (node_) {
00790       return RCPNodeHandle(node_, RCP_WEAK, false);
00791     }
00792     return RCPNodeHandle();
00793   }
00795   RCPNodeHandle create_strong() const {
00796     if (node_) {
00797       return RCPNodeHandle(node_, RCP_STRONG, false);
00798     }
00799     return RCPNodeHandle();
00800   }
00802   RCPNode* node_ptr() const {
00803     return node_;
00804   }
00806   bool is_node_null() const {
00807     return node_==0;
00808   }
00812   bool is_valid_ptr() const {
00813     if (node_) {
00814       return node_->is_valid_ptr();
00815     }
00816     return true; // Null is a valid ptr!
00817   }
00820   bool same_node(const RCPNodeHandle &node2) const {
00821     return node_ == node2.node_;
00822   }
00824   int strong_count() const {
00825     if (node_) {
00826       return node_->strong_count();
00827     }
00828     return 0;
00829   }
00831   int weak_count() const {
00832     if (node_) {
00833       return node_->weak_count();
00834     }
00835     return 0;
00836   }
00838   int total_count() const {
00839     if (node_) {
00840       return node_->strong_count() + node_->weak_count();
00841     }
00842     return 0;
00843   }
00845   int count() const {
00846     if (node_) {
00847       return node_->strong_count();
00848     }
00849     return 0;
00850   }
00852   ERCPStrength strength() const {
00853     return strength_;
00854   }
00856   void has_ownership(bool has_ownership_in)
00857     {
00858       if (node_)
00859         node_->has_ownership(has_ownership_in);
00860     }
00862   bool has_ownership() const
00863     {
00864       if (node_)
00865         return node_->has_ownership();
00866       return false;
00867     }
00869   void set_extra_data(
00870     const any &extra_data, const std::string& name,
00871     EPrePostDestruction destroy_when, bool force_unique
00872     )
00873     {
00874       debug_assert_not_null();
00875       node_->set_extra_data(extra_data, name, destroy_when, force_unique);
00876     }
00878   any& get_extra_data( const std::string& type_name,
00879     const std::string& name
00880     )
00881     {
00882       debug_assert_not_null();
00883       return node_->get_extra_data(type_name, name);
00884     }
00886   const any& get_extra_data( const std::string& type_name,
00887     const std::string& name
00888     ) const
00889     {
00890       return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
00891     }
00893   any* get_optional_extra_data(
00894     const std::string& type_name, const std::string& name
00895     )
00896     {
00897       debug_assert_not_null();
00898       return node_->get_optional_extra_data(type_name, name);
00899     }
00901   const any* get_optional_extra_data(
00902     const std::string& type_name, const std::string& name
00903     ) const
00904     {
00905       return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
00906     }
00908   void debug_assert_not_null() const
00909     {
00910 #ifdef TEUCHOS_DEBUG
00911       if (!node_)
00912         throw_null_ptr_error(typeName(*this));
00913 #endif
00914     }
00916   template<class RCPType>
00917   void assert_valid_ptr(const RCPType& rcp_obj) const
00918     {
00919       if (!node_)
00920         return; // Null is a valid pointer!
00921       if (!is_valid_ptr()) {
00922         node_->throw_invalid_obj_exception( typeName(rcp_obj),
00923           this, node_, rcp_obj.access_private_ptr() );
00924       }
00925     }
00927   template<class RCPType>
00928   void debug_assert_valid_ptr(const RCPType& rcp_obj) const
00929     {
00930 #ifdef TEUCHOS_DEBUG
00931       assert_valid_ptr(rcp_obj);
00932 #endif
00933     }
00934 #ifdef TEUCHOS_DEBUG
00935   const void* get_base_obj_map_key_void_ptr() const
00936     {
00937       if (node_)
00938         return node_->get_base_obj_map_key_void_ptr();
00939       return 0;
00940     }
00941 #endif
00942 private:
00943   RCPNode *node_;
00944   ERCPStrength strength_;
00945   inline void bind()
00946     {
00947       if (node_)
00948         node_->incr_count(strength_);
00949     }
00950   inline void unbind()
00951     {
00952       // Optimize this implementation for count > 1
00953       if (node_ && node_->deincr_count(strength_)==0) {
00954         // If we get here, the reference count has gone to 0 and something
00955         // interesting is going to happen.  In this case, we need to
00956         // reincrement the count back to 1 and call the more complex function
00957         // that will either delete the object or delete the node.
00958         node_->incr_count(strength_);
00959         unbindOne();
00960       }
00961       // If we get here, either node_==0 or the count is still greater than 0.
00962       // In this case, nothing interesting is going to happen so we are done!
00963     }
00964   void unbindOne(); // Provides the "strong" guarantee!
00965 
00966 };
00967 
00968 
00973 inline
00974 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
00975 {
00976   return (out << node.node_ptr());
00977 }
00978 
00979 
00989 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
00990 public:
00992   RCPNodeThrowDeleter(RCPNode *node)
00993     : node_(node)
00994     {}
01000   ~RCPNodeThrowDeleter()
01001     {
01002       if (node_) {
01003         node_->has_ownership(false); // Avoid actually deleting ptr_
01004         node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
01005         delete node_;
01006       }
01007     }
01009   RCPNode* get() const
01010     {
01011       return node_;
01012     }
01014   void release()
01015     {
01016       node_ = 0;
01017     }
01018 private:
01019   RCPNode *node_;
01020   RCPNodeThrowDeleter(); // Not defined
01021   RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
01022   RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
01023 };
01024 
01025 
01026 //
01027 // Unit testing support
01028 //
01029 
01030 
01031 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01032 
01033 class SetTracingActiveNodesStack {
01034 public:
01035   SetTracingActiveNodesStack()
01036     {RCPNodeTracer::setTracingActiveRCPNodes(true);}
01037   ~SetTracingActiveNodesStack()
01038     {RCPNodeTracer::setTracingActiveRCPNodes(false);}
01039 };
01040 
01041 #  define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
01042 
01043 #else
01044 
01045 #  define SET_RCPNODE_TRACING() (void)0
01046 
01047 #endif //  defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01048 
01049 
01050 } // end namespace Teuchos
01051 
01052 
01053 #endif // TEUCHOS_RCP_NODE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines