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       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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines