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_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_EXCEPT(true);
00095   }
00096 #endif
00097 }
00098 
00104 template<>
00105 class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
00106 public:
00107   static std::string toString( const ERCPStrength &t )
00108     {
00109       switch (t) {
00110         case RCP_STRONG:
00111           return "RCP_STRONG";
00112         case RCP_WEAK:
00113           return "RCP_WEAK";
00114         default:
00115           // Should never get here but fall through ...
00116           break;
00117       }
00118       // Should never get here!
00119 #ifdef TEUCHOS_DEBUG
00120       TEUCHOS_TEST_FOR_EXCEPT(true);
00121 #endif
00122       return "";
00123       // 2009/06/30: rabartl: The above logic avoid a warning from the Intel
00124       // 10.1 compiler (remark #111) about the statement being unreachable.
00125     }
00126 };
00127 
00128 
00140 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
00141 public:
00143   RCPNode(bool has_ownership_in)
00144     : has_ownership_(has_ownership_in), extra_data_map_(NULL)
00145 #ifdef TEUCHOS_DEBUG
00146     ,insertion_number_(-1)
00147 #endif // TEUCHOS_DEBUG
00148     {
00149       count_[RCP_STRONG] = 0;
00150       count_[RCP_WEAK] = 0;
00151     }
00153   virtual ~RCPNode()
00154     {
00155       if(extra_data_map_)
00156         delete extra_data_map_;
00157     }
00159   int strong_count() const
00160     {
00161       return count_[RCP_STRONG]; 
00162     }
00164   int weak_count() const
00165     {
00166       return count_[RCP_WEAK];
00167     }
00169   int incr_count( const ERCPStrength strength )
00170     {
00171       debugAssertStrength(strength);
00172       return ++count_[strength];
00173     }
00175   int deincr_count( const ERCPStrength strength )
00176     {
00177       debugAssertStrength(strength);
00178       return --count_[strength];
00179     }
00181   void has_ownership(bool has_ownership_in)
00182     {
00183       has_ownership_ = has_ownership_in;
00184     }
00186   bool has_ownership() const
00187     {
00188       return has_ownership_;
00189     }
00191   void set_extra_data(
00192     const any &extra_data, const std::string& name,
00193     EPrePostDestruction destroy_when, bool force_unique );
00195   any& get_extra_data( const std::string& type_name,
00196     const std::string& name );
00198   const any& get_extra_data( const std::string& type_name,
00199     const std::string& name
00200     ) const
00201     {
00202       return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
00203     }
00205   any* get_optional_extra_data(const std::string& type_name,
00206     const std::string& name );
00208   const any* get_optional_extra_data(
00209     const std::string& type_name, const std::string& name
00210     ) const
00211     {
00212       return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
00213     }
00215   virtual bool is_valid_ptr() const = 0;
00217   virtual void delete_obj() = 0;
00219   virtual void throw_invalid_obj_exception(
00220     const std::string& rcp_type_name,
00221     const void* rcp_ptr,
00222     const RCPNode* rcp_node_ptr,
00223     const void* rcp_obj_ptr
00224     ) const = 0;
00226   virtual const std::string get_base_obj_type_name() const = 0;
00227 #ifdef TEUCHOS_DEBUG
00228 
00229   virtual const void* get_base_obj_map_key_void_ptr() const = 0;
00230 #endif
00231 protected:
00233   void pre_delete_extra_data()
00234     {
00235       if(extra_data_map_)
00236         impl_pre_delete_extra_data();
00237     }
00238 private:
00239   struct extra_data_entry_t {
00240     extra_data_entry_t() : destroy_when(POST_DESTROY) {}
00241     extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
00242       : extra_data(_extra_data), destroy_when(_destroy_when)
00243       {}
00244     any extra_data;
00245     EPrePostDestruction destroy_when;
00246   }; 
00247   typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
00248   int count_[2];
00249   bool has_ownership_;
00250   extra_data_map_t *extra_data_map_;
00251   // Above is made a pointer to reduce overhead for the general case when this
00252   // is not used.  However, this adds just a little bit to the overhead when
00253   // it is used.
00254   // Provides the "basic" guarantee!
00255   void impl_pre_delete_extra_data();
00256   // Not defined and not to be called
00257   RCPNode();
00258   RCPNode(const RCPNode&);
00259   RCPNode& operator=(const RCPNode&);
00260 #ifdef TEUCHOS_DEBUG
00261   int insertion_number_;
00262 public:
00263   void set_insertion_number(int insertion_number_in)
00264     {
00265       insertion_number_ = insertion_number_in;
00266     }
00267   int insertion_number() const
00268     {
00269       return insertion_number_;
00270     }
00271 #endif // TEUCHOS_DEBUG
00272 };
00273 
00274 
00279 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
00280 
00281 
00298 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
00299 public:
00300 
00303 
00305   struct RCPNodeStatistics {
00306     RCPNodeStatistics()
00307       : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
00308         totalNumRCPNodeDeletions(0)
00309       {}
00310     long int maxNumRCPNodes;
00311     long int totalNumRCPNodeAllocations;
00312     long int totalNumRCPNodeDeletions;
00313   };
00314 
00316 
00319 
00325   static bool isTracingActiveRCPNodes();
00326 
00327 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
00328 
00345   static void setTracingActiveRCPNodes(bool tracingActiveNodes);
00346 #endif
00347 
00351   static int numActiveRCPNodes();
00352 
00354   static RCPNodeStatistics getRCPNodeStatistics() ;
00355 
00357   static void printRCPNodeStatistics(
00358     const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
00359 
00363   static void setPrintRCPNodeStatisticsOnExit(
00364     bool printRCPNodeStatisticsOnExit);
00365 
00369   static bool getPrintRCPNodeStatisticsOnExit();
00370 
00385   static void printActiveRCPNodes(std::ostream &out);
00386 
00388 
00393 
00398   static void addNewRCPNode(RCPNode* rcp_node,
00399     const std::string &info );
00400 
00406   static void removeRCPNode( RCPNode* rcp_node );
00407 
00416   template<class T>
00417   static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
00418     {
00419 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
00420       return getBaseObjVoidPtr(p);
00421 #else
00422       // This will not return the base address for polymorphic types if
00423       // multiple inheritance and/or virtual bases are used but returning the
00424       // static_cast should be okay in how it is used.  It is just that the
00425       // RCPNode tracing support will not always be able to figure out if two
00426       // pointers of different type are pointing to the same object or not.
00427       return static_cast<const void*>(p);
00428 #endif
00429     }
00430 
00437   static RCPNode* getExistingRCPNodeGivenLookupKey(
00438     const void* lookupKey);
00439 
00446   template<class T>
00447   static RCPNode* getExistingRCPNode(T *p)
00448     {
00449       return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
00450     }
00451 
00453   static std::string getActiveRCPNodeHeaderString();
00454 
00456   static std::string getCommonDebugNotesString();
00457 
00459 
00460 };
00461 
00462 
00463 #ifdef TEUCHOS_DEBUG
00464 #  define TEUCHOS_RCP_INSERION_NUMBER_STR() \
00465       "  insertionNumber:      " << rcp_node_ptr->insertion_number() << "\n"
00466 #else
00467 #  define TEUCHOS_RCP_INSERION_NUMBER_STR()
00468 #endif
00469 
00470 
00476 template<class T, class Dealloc_T>
00477 class RCPNodeTmpl : public RCPNode {
00478 public:
00480   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
00481     : RCPNode(has_ownership_in), ptr_(p),
00482 #ifdef TEUCHOS_DEBUG
00483       base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
00484       deleted_ptr_(0),
00485 #endif
00486       dealloc_(dealloc)
00487     {}
00489   RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
00490     : RCPNode(has_ownership_in), ptr_(p),
00491 #ifdef TEUCHOS_DEBUG
00492       base_obj_map_key_void_ptr_(0),
00493       deleted_ptr_(0),
00494 #endif
00495       dealloc_(dealloc)
00496     {}
00498   Dealloc_T& get_nonconst_dealloc()
00499     { return dealloc_; }
00501   const Dealloc_T& get_dealloc() const
00502     { return dealloc_; }
00504   ~RCPNodeTmpl()
00505     {
00506 #ifdef TEUCHOS_DEBUG
00507       TEUCHOS_TEST_FOR_EXCEPTION( ptr_!=0, std::logic_error,
00508         "Error, the underlying object must be explicitly deleted before deleting"
00509         " the node object!" );
00510 #endif
00511     }
00513   virtual bool is_valid_ptr() const
00514     {
00515       return ptr_ != 0;
00516     }
00522   virtual void delete_obj()
00523     {
00524       if (ptr_!= 0) {
00525         this->pre_delete_extra_data(); // May throw!
00526         T* tmp_ptr = ptr_;
00527 #ifdef TEUCHOS_DEBUG
00528         deleted_ptr_ = tmp_ptr;
00529 #endif
00530         ptr_ = 0;
00531         if (has_ownership()) {
00532 #ifdef TEUCHOS_DEBUG
00533           try {
00534 #endif
00535             dealloc_.free(tmp_ptr);
00536 #ifdef TEUCHOS_DEBUG
00537           }
00538           catch(...) {
00539             // Object was not deleted due to an exception!
00540             ptr_ = tmp_ptr;
00541             throw;
00542           }
00543 #endif
00544         }
00545         // 2008/09/22: rabartl: Above, we have to be careful to set the member
00546         // this->ptr_=0 before calling delete on the object's address in order
00547         // to avoid a double call to delete in cases of circular references
00548         // involving weak and strong pointers (see the unit test
00549         // circularReference_c_then_a in RCP_UnitTests.cpp).  NOTE: It is
00550         // critcial that no member of *this get accesses after
00551         // dealloc_.free(...) gets called!  Also, in order to provide the
00552         // "strong" guarantee we have to include the above try/catch.  This
00553         // overhead is unfortunate but I don't know of any other way to
00554         // statisfy the "strong" guarantee and still avoid a double delete.
00555       }
00556     }
00558   virtual void throw_invalid_obj_exception(
00559     const std::string& rcp_type_name,
00560     const void* rcp_ptr,
00561     const RCPNode* rcp_node_ptr,
00562     const void* rcp_obj_ptr
00563     ) const
00564     {
00565       TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
00566       const T* deleted_ptr =
00567 #ifdef TEUCHOS_DEBUG
00568         deleted_ptr_
00569 #else
00570         0
00571 #endif
00572         ;
00573       TEUCHOS_ASSERT(rcp_node_ptr);
00574       TEUCHOS_TEST_FOR_EXCEPTION( true, DanglingReferenceError,
00575         "Error, an attempt has been made to dereference the underlying object\n"
00576         "from a weak smart pointer object where the underling object has already\n"
00577         "been deleted since the strong count has already gone to zero.\n"
00578         "\n"
00579         "Context information:\n"
00580         "\n"
00581         "  RCP type:             " << rcp_type_name << "\n"
00582         "  RCP address:          " << rcp_ptr << "\n"
00583         "  RCPNode type:         " << typeName(*this) << "\n"
00584         "  RCPNode address:      " << rcp_node_ptr << "\n"
00585         TEUCHOS_RCP_INSERION_NUMBER_STR()
00586         "  RCP ptr address:      " << rcp_obj_ptr << "\n"
00587         "  Concrete ptr address: " << deleted_ptr << "\n"
00588         "\n"
00589         << RCPNodeTracer::getCommonDebugNotesString()
00590         );
00591       // 2008/09/22: rabartl: Above, we do not provide the concreate object
00592       // type or the concrete object address.  In the case of the concrete
00593       // object address, in a non-debug build, we don't want to pay a price
00594       // for extra storage that we strictly don't need.  In the case of the
00595       // concrete object type name, we don't want to force non-debug built
00596       // code to have the require that types be fully defined in order to use
00597       // the memory management software.  This is related to bug 4016.
00598 
00599     }
00601   const std::string get_base_obj_type_name() const
00602     {
00603 #ifdef TEUCHOS_DEBUG
00604       return TypeNameTraits<T>::name();
00605 #else
00606       return "UnknownType";
00607 #endif
00608     }
00609 #ifdef TEUCHOS_DEBUG
00610 
00611   const void* get_base_obj_map_key_void_ptr() const
00612     {
00613       return base_obj_map_key_void_ptr_;
00614     }
00615 #endif
00616 private:
00617   T *ptr_;
00618 #ifdef TEUCHOS_DEBUG
00619   const void *base_obj_map_key_void_ptr_;
00620   T *deleted_ptr_;
00621 #endif
00622   Dealloc_T dealloc_;
00623   // not defined and not to be called
00624   RCPNodeTmpl();
00625   RCPNodeTmpl(const RCPNodeTmpl&);
00626   RCPNodeTmpl& operator=(const RCPNodeTmpl&);
00627 
00628 }; // end class RCPNodeTmpl<T>
00629 
00630 
00638 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
00639 public:
00641   ActiveRCPNodesSetup();
00643   ~ActiveRCPNodesSetup();
00645   void foo();
00646 private:
00647   static int count_;
00648 };
00649 
00650 
00651 } // namespace Teuchos
00652 
00653 
00654 namespace {
00655 // This static variable is delcared before all other static variables that
00656 // depend on RCP or other classes. Therefore, this static varaible will be
00657 // deleted *after* all of these other static variables that depend on RCP or
00658 // created classes go away!  This ensures that the node tracing machinery is
00659 // setup and torn down correctly (this is the same trick used by the standard
00660 // stream objects in many compiler implementations).
00661 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
00662 } // namespace
00663 
00664 
00665 namespace Teuchos {
00666 
00667 
00683 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
00684 public:
00686   RCPNodeHandle(ENull null_arg = null)
00687     : node_(0), strength_(RCP_STRONG)
00688     {(void)null_arg;}
00690   RCPNodeHandle( RCPNode* node, ERCPStrength strength_in = RCP_STRONG,
00691     bool newNode = true
00692     )
00693     : node_(node), strength_(strength_in)
00694     {
00695 #ifdef TEUCHOS_DEBUG
00696       TEUCHOS_ASSERT(node);
00697 #endif
00698       bind();
00699 #ifdef TEUCHOS_DEBUG
00700       // Add the node if this is the first RCPNodeHandle to get it.  We have
00701       // to add it because unbind() will call the remove_RCPNode(...) function
00702       // and it needs to match when node tracing is on from the beginning.
00703       if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode)
00704       {
00705         std::ostringstream os;
00706         os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
00707            << " has_ownership="<<node_->has_ownership()<<"}";
00708         RCPNodeTracer::addNewRCPNode(node_, os.str());
00709       }
00710 #endif
00711     }
00712 #ifdef TEUCHOS_DEBUG
00713 
00714   template<typename T>
00715   RCPNodeHandle(RCPNode* node, T *p, const std::string &T_name,
00716     const std::string &ConcreteT_name, const bool has_ownership_in,
00717     ERCPStrength strength_in = RCP_STRONG
00718     )
00719     : node_(node), strength_(strength_in)
00720     {
00721       TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
00722       TEUCHOS_ASSERT(node_);
00723       bind();
00724       if (RCPNodeTracer::isTracingActiveRCPNodes()) {
00725         std::ostringstream os;
00726         os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
00727            <<", p="<<static_cast<const void*>(p)
00728            <<", has_ownership="<<has_ownership_in<<"}";
00729         RCPNodeTracer::addNewRCPNode(node_, os.str());
00730       }
00731     }
00732 #endif // TEUCHOS_DEBUG
00733 
00734   RCPNodeHandle(const RCPNodeHandle& node_ref)
00735     : node_(node_ref.node_), strength_(node_ref.strength_)
00736     {
00737       bind();
00738     }
00740   void swap( RCPNodeHandle& node_ref )
00741     {
00742       std::swap(node_ref.node_, node_);
00743       std::swap(node_ref.strength_, strength_);
00744     }
00746   RCPNodeHandle& operator=(const RCPNodeHandle& node_ref)
00747     {
00748       // Assignment to self check: Note, We don't need to do an assigment to
00749       // self check here because such a check is already done in the RCP and
00750       // ArrayRCP classes.
00751       // Take care of this's existing node and object
00752       unbind(); // May throw in some cases
00753       // Assign the new node
00754       node_ = node_ref.node_;
00755       strength_ = node_ref.strength_;
00756       bind();
00757       // Return
00758       return *this;
00759     }
00761   ~RCPNodeHandle()
00762     {
00763       unbind();
00764     }
00766   RCPNodeHandle create_weak() const
00767     {
00768       if (node_) {
00769         return RCPNodeHandle(node_, RCP_WEAK, false);
00770       }
00771       return RCPNodeHandle();
00772     }
00774   RCPNodeHandle create_strong() const
00775     {
00776       if (node_) {
00777         return RCPNodeHandle(node_, RCP_STRONG, false);
00778       }
00779       return RCPNodeHandle();
00780     }
00782   RCPNode* node_ptr() const
00783     {
00784       return node_;
00785     }
00787   bool is_node_null() const
00788     {
00789       return node_==0;
00790     }
00792   bool is_valid_ptr() const
00793     {
00794       if (node_)
00795         return node_->is_valid_ptr();
00796       return true; // Null is a valid ptr!
00797     }
00799   bool same_node(const RCPNodeHandle &node2) const
00800     {
00801       return node_ == node2.node_;
00802     }
00804   int strong_count() const
00805     {
00806       if (node_)
00807         return node_->strong_count(); 
00808       return 0;
00809     }
00811   int weak_count() const
00812     {
00813       if (node_)
00814         return node_->weak_count(); 
00815       return 0;
00816     }
00818   int total_count() const
00819     {
00820       if (node_)
00821         return node_->strong_count() + node_->weak_count(); 
00822       return 0;
00823     }
00825   int count() const
00826     {
00827       if (node_)
00828         return node_->strong_count(); 
00829       return 0;
00830     }
00832   ERCPStrength strength() const
00833     {
00834       return strength_;
00835     }
00837   void has_ownership(bool has_ownership_in)
00838     {
00839       if (node_)
00840         node_->has_ownership(has_ownership_in);
00841     }
00843   bool has_ownership() const
00844     {
00845       if (node_)
00846         return node_->has_ownership();
00847       return false;
00848     }
00850   void set_extra_data(
00851     const any &extra_data, const std::string& name,
00852     EPrePostDestruction destroy_when, bool force_unique
00853     )
00854     {
00855       debug_assert_not_null();
00856       node_->set_extra_data(extra_data, name, destroy_when, force_unique);
00857     }
00859   any& get_extra_data( const std::string& type_name,
00860     const std::string& name
00861     )
00862     {
00863       debug_assert_not_null();
00864       return node_->get_extra_data(type_name, name);
00865     } 
00867   const any& get_extra_data( const std::string& type_name,
00868     const std::string& name 
00869     ) const
00870     {
00871       return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
00872     }
00874   any* get_optional_extra_data(
00875     const std::string& type_name, const std::string& name
00876     )
00877     {
00878       debug_assert_not_null();
00879       return node_->get_optional_extra_data(type_name, name);
00880     } 
00882   const any* get_optional_extra_data(
00883     const std::string& type_name, const std::string& name
00884     ) const
00885     {
00886       return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
00887     }
00889   void debug_assert_not_null() const
00890     {
00891 #ifdef TEUCHOS_DEBUG
00892       if (!node_)
00893         throw_null_ptr_error(typeName(*this));
00894 #endif
00895     }
00897   template<class RCPType>
00898   void assert_valid_ptr(const RCPType& rcp_obj) const
00899     {
00900       if (!node_)
00901         return; // Null is a valid pointer!
00902       if (!is_valid_ptr()) {
00903         node_->throw_invalid_obj_exception( typeName(rcp_obj),
00904           this, node_, rcp_obj.access_private_ptr() );
00905       }
00906     }
00908   template<class RCPType>
00909   void debug_assert_valid_ptr(const RCPType& rcp_obj) const
00910     {
00911 #ifdef TEUCHOS_DEBUG
00912       assert_valid_ptr(rcp_obj);
00913 #endif
00914     }
00915 #ifdef TEUCHOS_DEBUG
00916   const void* get_base_obj_map_key_void_ptr() const
00917     {
00918       if (node_)
00919         return node_->get_base_obj_map_key_void_ptr();
00920       return 0;
00921     }
00922 #endif
00923 private:
00924   RCPNode *node_;
00925   ERCPStrength strength_;
00926   inline void bind()
00927     {
00928       if (node_)
00929         node_->incr_count(strength_);
00930     }
00931   inline void unbind() 
00932     {
00933       // Optimize this implementation for count > 1
00934       if (node_ && node_->deincr_count(strength_)==0) {
00935         // If we get here, the reference count has gone to 0 and something
00936         // interesting is going to happen.  In this case, we need to
00937         // reincrement the count back to 1 and call the more complex function
00938         // that will either delete the object or delete the node.
00939         node_->incr_count(strength_);
00940         unbindOne();
00941       }
00942       // If we get here, either node_==0 or the count is still greater than 0.
00943       // In this case, nothing interesting is going to happen so we are done!
00944     }
00945   void unbindOne(); // Provides the "strong" guarantee!
00946 
00947 };
00948 
00949 
00954 inline
00955 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
00956 {
00957   return (out << node.node_ptr());
00958 }
00959 
00960 
00970 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
00971 public:
00973   RCPNodeThrowDeleter(RCPNode *node)
00974     : node_(node)
00975     {}
00981   ~RCPNodeThrowDeleter()
00982     {
00983       if (node_) {
00984         node_->has_ownership(false); // Avoid actually deleting ptr_
00985         node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
00986         delete node_;
00987       }
00988     }
00990   RCPNode* get() const
00991     {
00992       return node_;
00993     }
00995   void release()
00996     {
00997       node_ = 0;
00998     }
00999 private:
01000   RCPNode *node_;
01001   RCPNodeThrowDeleter(); // Not defined
01002   RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
01003   RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
01004 };
01005 
01006 
01007 //
01008 // Unit testing support
01009 //
01010 
01011 
01012 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01013 
01014 class SetTracingActiveNodesStack {
01015 public: 
01016   SetTracingActiveNodesStack()
01017     {RCPNodeTracer::setTracingActiveRCPNodes(true);}
01018   ~SetTracingActiveNodesStack()
01019     {RCPNodeTracer::setTracingActiveRCPNodes(false);}
01020 };
01021 
01022 #  define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
01023 
01024 #else
01025 
01026 #  define SET_RCPNODE_TRACING() (void)0
01027 
01028 #endif //  defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
01029 
01030 
01031 } // end namespace Teuchos
01032 
01033 
01034 #endif // TEUCHOS_RCP_NODE_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines