Teuchos - Trilinos Tools Package 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_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       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_STRONG";
00117         default:
00118           // Should never get here but fall through ...
00119           break;
00120       }
00121       // Should never get here!
00122 #ifdef TEUCHOS_DEBUG
00123       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 count( const ERCPStrength strength )
00173     {
00174       debugAssertStrength(strength);
00175       return count_[strength];
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 TEUCHOS_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
00289 
00290 
00307 class TEUCHOS_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       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       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       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 TEUCHOS_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 delcared before all other static variables that
00665 // depend on RCP or other classes. Therefore, this static varaible 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
00672 
00673 
00674 namespace Teuchos {
00675 
00676 
00692 class TEUCHOS_LIB_DLL_EXPORT RCPNodeHandle {
00693 public:
00695   RCPNodeHandle(ENull null_arg = null)
00696     : node_(0), strength_(RCP_STRENGTH_INVALID)
00697     {(void)null_arg;}
00699   RCPNodeHandle( RCPNode* node, ERCPStrength strength_in = RCP_STRONG,
00700     bool newNode = true
00701     )
00702     : node_(node), strength_(strength_in)
00703     {
00704 #ifdef TEUCHOS_DEBUG
00705       TEUCHOS_ASSERT(node);
00706 #endif
00707       bind();
00708 #ifdef TEUCHOS_DEBUG
00709       // Add the node if this is the first RCPNodeHandle to get it.  We have
00710       // to add it because unbind() will call the remove_RCPNode(...) function
00711       // and it needs to match when node tracing is on from the beginning.
00712       if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode)
00713       {
00714         std::ostringstream os;
00715         os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
00716            << " has_ownership="<<node_->has_ownership()<<"}";
00717         RCPNodeTracer::addNewRCPNode(node_, os.str());
00718       }
00719 #endif
00720     }
00721 #ifdef TEUCHOS_DEBUG
00722 
00723   template<typename T>
00724   RCPNodeHandle(RCPNode* node, T *p, const std::string &T_name,
00725     const std::string &ConcreteT_name, const bool has_ownership_in,
00726     ERCPStrength strength_in = RCP_STRONG
00727     )
00728     : node_(node), strength_(strength_in)
00729     {
00730       TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
00731       TEUCHOS_ASSERT(node_);
00732       bind();
00733       if (RCPNodeTracer::isTracingActiveRCPNodes()) {
00734         std::ostringstream os;
00735         os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
00736            <<", p="<<static_cast<const void*>(p)
00737            <<", has_ownership="<<has_ownership_in<<"}";
00738         RCPNodeTracer::addNewRCPNode(node_, os.str());
00739       }
00740     }
00741 #endif // TEUCHOS_DEBUG
00742 
00743   RCPNodeHandle(const RCPNodeHandle& node_ref)
00744     : node_(node_ref.node_), strength_(node_ref.strength_)
00745     {
00746       bind();
00747     }
00749   void swap( RCPNodeHandle& node_ref )
00750     {
00751       std::swap(node_ref.node_, node_);
00752       std::swap(node_ref.strength_, strength_);
00753     }
00755   RCPNodeHandle& operator=(const RCPNodeHandle& node_ref)
00756     {
00757       // Assignment to self check: Note, We don't need to do an assigment to
00758       // self check here because such a check is already done in the RCP and
00759       // ArrayRCP classes.
00760       // Take care of this's existing node and object
00761       unbind(); // May throw in some cases
00762       // Assign the new node
00763       node_ = node_ref.node_;
00764       strength_ = node_ref.strength_;
00765       bind();
00766       // Return
00767       return *this;
00768     }
00770   ~RCPNodeHandle()
00771     {
00772       unbind();
00773     }
00775   RCPNodeHandle create_weak() const
00776     {
00777       if (node_) {
00778         return RCPNodeHandle(node_, RCP_WEAK, false);
00779       }
00780       return RCPNodeHandle();
00781     }
00783   RCPNodeHandle create_strong() const
00784     {
00785       if (node_) {
00786         return RCPNodeHandle(node_, RCP_STRONG, false);
00787       }
00788       return RCPNodeHandle();
00789     }
00791   RCPNode* node_ptr() const
00792     {
00793       return node_;
00794     }
00796   bool is_node_null() const
00797     {
00798       return node_==0;
00799     }
00801   bool is_valid_ptr() const
00802     {
00803       if (node_)
00804         return node_->is_valid_ptr();
00805       return true; // Null is a valid ptr!
00806     }
00808   bool same_node(const RCPNodeHandle &node2) const
00809     {
00810       return node_ == node2.node_;
00811     }
00813   int strong_count() const
00814     {
00815       if (node_)
00816         return node_->strong_count(); 
00817       return 0;
00818     }
00820   int weak_count() const
00821     {
00822       if (node_)
00823         return node_->weak_count(); 
00824       return 0;
00825     }
00827   int total_count() const
00828     {
00829       if (node_)
00830         return node_->strong_count() + node_->weak_count(); 
00831       return 0;
00832     }
00834   int count() const
00835     {
00836       if (node_)
00837         return node_->strong_count(); 
00838       return 0;
00839     }
00841   ERCPStrength strength() const
00842     {
00843       return strength_;
00844     }
00846   void has_ownership(bool has_ownership_in)
00847     {
00848       if (node_)
00849         node_->has_ownership(has_ownership_in);
00850     }
00852   bool has_ownership() const
00853     {
00854       if (node_)
00855         return node_->has_ownership();
00856       return false;
00857     }
00859   void set_extra_data(
00860     const any &extra_data, const std::string& name,
00861     EPrePostDestruction destroy_when, bool force_unique
00862     )
00863     {
00864       debug_assert_not_null();
00865       node_->set_extra_data(extra_data, name, destroy_when, force_unique);
00866     }
00868   any& get_extra_data( const std::string& type_name,
00869     const std::string& name
00870     )
00871     {
00872       debug_assert_not_null();
00873       return node_->get_extra_data(type_name, name);
00874     } 
00876   const any& get_extra_data( const std::string& type_name,
00877     const std::string& name 
00878     ) const
00879     {
00880       return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
00881     }
00883   any* get_optional_extra_data(
00884     const std::string& type_name, const std::string& name
00885     )
00886     {
00887       debug_assert_not_null();
00888       return node_->get_optional_extra_data(type_name, name);
00889     } 
00891   const any* get_optional_extra_data(
00892     const std::string& type_name, const std::string& name
00893     ) const
00894     {
00895       return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
00896     }
00898   void debug_assert_not_null() const
00899     {
00900 #ifdef TEUCHOS_DEBUG
00901       if (!node_)
00902         throw_null_ptr_error(typeName(*this));
00903 #endif
00904     }
00906   template<class RCPType>
00907   void assert_valid_ptr(const RCPType& rcp_obj) const
00908     {
00909       if (!node_)
00910         return; // Null is a valid pointer!
00911       if (!is_valid_ptr()) {
00912         node_->throw_invalid_obj_exception( typeName(rcp_obj),
00913           this, node_, rcp_obj.access_private_ptr() );
00914       }
00915     }
00917   template<class RCPType>
00918   void debug_assert_valid_ptr(const RCPType& rcp_obj) const
00919     {
00920 #ifdef TEUCHOS_DEBUG
00921       assert_valid_ptr(rcp_obj);
00922 #endif
00923     }
00924 #ifdef TEUCHOS_DEBUG
00925   const void* get_base_obj_map_key_void_ptr() const
00926     {
00927       if (node_)
00928         return node_->get_base_obj_map_key_void_ptr();
00929       return 0;
00930     }
00931 #endif
00932 private:
00933   RCPNode *node_;
00934   ERCPStrength strength_;
00935   inline void bind()
00936     {
00937       if (node_)
00938         node_->incr_count(strength_);
00939     }
00940   inline void unbind() 
00941     {
00942       // Optimize this implementation for count > 1
00943       if (node_ && node_->deincr_count(strength_)==0) {
00944         // If we get here, the reference count has gone to 0 and something
00945         // interesting is going to happen.  In this case, we need to
00946         // reincrement the count back to 1 and call the more complex function
00947         // that will either delete the object or delete the node.
00948         node_->incr_count(strength_);
00949         unbindOne();
00950       }
00951       // If we get here, either node_==0 or the count is still greater than 0.
00952       // In this case, nothing interesting is going to happen so we are done!
00953     }
00954   void unbindOne(); // Provides the "strong" guarantee!
00955 
00956 };
00957 
00958 
00963 inline
00964 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
00965 {
00966   return (out << node.node_ptr());
00967 }
00968 
00969 
00979 class TEUCHOS_LIB_DLL_EXPORT RCPNodeThrowDeleter {
00980 public:
00982   RCPNodeThrowDeleter(RCPNode *node)
00983     : node_(node)
00984     {}
00990   ~RCPNodeThrowDeleter()
00991     {
00992       if (node_) {
00993         node_->has_ownership(false); // Avoid actually deleting ptr_
00994         node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
00995         delete node_;
00996       }
00997     }
00999   RCPNode* get() const
01000     {
01001       return node_;
01002     }
01004   void release()
01005     {
01006       node_ = 0;
01007     }
01008 private:
01009   RCPNode *node_;
01010   RCPNodeThrowDeleter(); // Not defined
01011   RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
01012   RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
01013 };
01014 
01015 
01016 //
01017 // Unit testing support
01018 //
01019 
01020 
01021 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01022 
01023 class SetTracingActiveNodesStack {
01024 public: 
01025   SetTracingActiveNodesStack()
01026     {RCPNodeTracer::setTracingActiveRCPNodes(true);}
01027   ~SetTracingActiveNodesStack()
01028     {RCPNodeTracer::setTracingActiveRCPNodes(false);}
01029 };
01030 
01031 #  define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
01032 
01033 #else
01034 
01035 #  define SET_RCPNODE_TRACING() (void)0
01036 
01037 #endif //  defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01038 
01039 
01040 } // end namespace Teuchos
01041 
01042 
01043 #endif // TEUCHOS_RCP_NODE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines