Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_RCPNode.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_RCP_NODE_HPP
43 #define TEUCHOS_RCP_NODE_HPP
44 
45 
52 #include "Teuchos_ConfigDefs.hpp"
53 #include "Teuchos_any.hpp"
54 #include "Teuchos_map.hpp"
55 #include "Teuchos_ENull.hpp"
56 #include "Teuchos_Assert.hpp"
57 #include "Teuchos_Exceptions.hpp"
59 #include "Teuchos_toString.hpp"
60 #include "Teuchos_getBaseObjVoidPtr.hpp"
61 
62 #if defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE) && !defined(DISABLE_ATOMIC_COUNTERS)
63 #include <atomic>
64 #define USING_ATOMICS
65 #endif
66 
67 namespace Teuchos {
68 
69 #ifdef USING_ATOMICS
70 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) std::atomic<T> VAR
71 #else
72 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) T VAR
73 #endif
74 
79 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
80 
85 enum ERCPStrength { RCP_STRONG=0, RCP_WEAK=1 };
86 
91 enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP };
92 
94 inline void debugAssertStrength(ERCPStrength strength)
95 {
96 #ifdef TEUCHOS_DEBUG
97  switch (strength) {
98  case RCP_STRONG:
99  // fall through
100  case RCP_WEAK:
101  return; // Fine
102  default:
104  true, std::logic_error, "Teuchos::RCPNode: ERCPStrength enum value "
105  << strength << " is invalid (neither RCP_STRONG = " << RCP_STRONG
106  << " nor RCP_WEAK = " << RCP_WEAK << ").");
107  }
108 #else
109  (void) strength; // Silence "unused variable" compiler warning.
110 #endif // TEUCHOS_DEBUG
111 }
112 
118 template<>
119 class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
120 public:
121  static std::string toString( const ERCPStrength &t )
122  {
123  switch (t) {
124  case RCP_STRONG:
125  return "RCP_STRONG";
126  case RCP_WEAK:
127  return "RCP_WEAK";
128  default:
129  // Should never get here but fall through ...
130  break;
131  }
132  // Should never get here!
133 #ifdef TEUCHOS_DEBUG
135 #else
136  return "";
137 #endif
138  }
139 };
140 
141 
153 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
154 public:
156  RCPNode(bool has_ownership_in)
157  : has_ownership_(has_ownership_in), extra_data_map_(NULL)
158 #ifdef TEUCHOS_DEBUG
159  ,insertion_number_(-1)
160 #endif // TEUCHOS_DEBUG
161  {
162  count_[RCP_STRONG] = 0;
163  count_[RCP_WEAK] = 0;
164  }
166  virtual ~RCPNode()
167  {
168  if(extra_data_map_)
169  delete extra_data_map_;
170  }
175  {
176 #ifdef USING_ATOMICS
177  // this code follows the boost method
178  int strong_count_non_atomic = count_[RCP_STRONG];
179  for( ;; ) {
180  if (strong_count_non_atomic == 0) {
181  return false;
182  }
183  if (std::atomic_compare_exchange_weak( &count_[RCP_STRONG],
184  &strong_count_non_atomic, strong_count_non_atomic + 1)) {
185  return true;
186  }
187  }
188 #else
189  // the non-thread safe version - this fails with threads because
190  // strong_count_ can become 0 after the check if it is 0 and we would
191  // return true with no valid object
192  if (count_[RCP_STRONG] == 0) {
193  return false;
194  }
195  else {
196  ++count_[RCP_STRONG];
197  return true;
198  }
199 #endif
200  }
202  int strong_count() const
203  {
204  return count_[RCP_STRONG];
205  }
207  int weak_count() const // not atomically safe
208  {
209  return count_[RCP_WEAK] - (count_[RCP_STRONG] ? 1 : 0 ); // weak is +1 when strong > 0
210  }
212  void incr_count( const ERCPStrength strength )
213  {
214  debugAssertStrength(strength);
215  if (++count_[strength] == 1) {
216  if (strength == RCP_STRONG) {
217  ++count_[RCP_WEAK]; // this is the special condition - the first strong creates a weak
218  }
219  }
220  }
222  int deincr_count( const ERCPStrength strength )
223  {
224  debugAssertStrength(strength);
225 #ifdef BREAK_THREAD_SAFETY_OF_DEINCR_COUNT
226  --count_[strength];
227  return count_[strength]; // not atomically valid
228 #else
229  return --count_[strength];
230 #endif
231  }
233  void has_ownership(bool has_ownership_in)
234  {
235  has_ownership_ = has_ownership_in;
236  }
238  bool has_ownership() const
239  {
240  return has_ownership_;
241  }
243  void set_extra_data(
244  const any &extra_data, const std::string& name,
245  EPrePostDestruction destroy_when, bool force_unique );
247  any& get_extra_data( const std::string& type_name,
248  const std::string& name );
250  const any& get_extra_data( const std::string& type_name,
251  const std::string& name
252  ) const
253  {
254  return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
255  }
257  any* get_optional_extra_data(const std::string& type_name,
258  const std::string& name );
261  const std::string& type_name, const std::string& name
262  ) const
263  {
264  return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
265  }
267  virtual bool is_valid_ptr() const = 0;
269  virtual void delete_obj() = 0;
271  virtual void throw_invalid_obj_exception(
272  const std::string& rcp_type_name,
273  const void* rcp_ptr,
274  const RCPNode* rcp_node_ptr,
275  const void* rcp_obj_ptr
276  ) const = 0;
278  virtual const std::string get_base_obj_type_name() const = 0;
279 #ifdef TEUCHOS_DEBUG
280 
281  virtual const void* get_base_obj_map_key_void_ptr() const = 0;
282 #endif
283 protected:
286  {
287  if(extra_data_map_)
288  impl_pre_delete_extra_data();
289  }
290 private:
291  struct extra_data_entry_t {
292  extra_data_entry_t() : destroy_when(POST_DESTROY) {}
293  extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
294  : extra_data(_extra_data), destroy_when(_destroy_when)
295  {}
296  any extra_data;
297  EPrePostDestruction destroy_when;
298  };
299  typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
300 
301  TEUCHOS_RCP_DECL_ATOMIC(count_[2], int);
302  TEUCHOS_RCP_DECL_ATOMIC(has_ownership_, bool);
303 
304  extra_data_map_t *extra_data_map_;
305  // Above is made a pointer to reduce overhead for the general case when this
306  // is not used. However, this adds just a little bit to the overhead when
307  // it is used.
308  // Provides the "basic" guarantee!
309  void impl_pre_delete_extra_data();
310  // Not defined and not to be called
311  RCPNode();
312  RCPNode(const RCPNode&);
313  RCPNode& operator=(const RCPNode&);
314 #ifdef TEUCHOS_DEBUG
315  // removed atomic because mutex handles it - atomic would be redundant
316  int insertion_number_;
317 public:
318  void set_insertion_number(int insertion_number_in)
319  {
320  insertion_number_ = insertion_number_in;
321  }
322  int insertion_number() const
323  {
324  return insertion_number_;
325  }
326 #endif // TEUCHOS_DEBUG
327 };
328 
329 
334 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
335 
336 
337 #ifdef TEUCHOS_DEBUG
338  // to fully implement abort for TEUCHOS_STANDARD_CATCH_STATEMENTS in the cpp
340  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const std::exception &);
342  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const int &);
344  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor();
345  // called when RCPNode detects any exception in a destructor
346  #define TEUCHOS_CATCH_AND_ABORT \
347  catch(const std::exception &excpt) { abort_for_exception_in_destructor(excpt); } \
348  catch(const int &excpt_code) { abort_for_exception_in_destructor(excpt_code); } \
349  catch(...) { abort_for_exception_in_destructor(); }
350 #endif
351 
368 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
369 public:
370 
373 
377  : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
378  totalNumRCPNodeDeletions(0)
379  {}
380  long int maxNumRCPNodes;
381  long int totalNumRCPNodeAllocations;
382  long int totalNumRCPNodeDeletions;
383  };
384 
386 
389 
395  static bool isTracingActiveRCPNodes();
396 
397 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
398 
415  static void setTracingActiveRCPNodes(bool tracingActiveNodes);
416 #endif
417 
421  static int numActiveRCPNodes();
422 
424  static RCPNodeStatistics getRCPNodeStatistics() ;
425 
427  static void printRCPNodeStatistics(
428  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
429 
433  static void setPrintRCPNodeStatisticsOnExit(
434  bool printRCPNodeStatisticsOnExit);
435 
439  static bool getPrintRCPNodeStatisticsOnExit();
440 
444  static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit);
445 
449  static bool getPrintActiveRcpNodesOnExit();
450 
466  static void printActiveRCPNodes(std::ostream &out);
467 
469 
474 
479  static void addNewRCPNode(RCPNode* rcp_node,
480  const std::string &info );
481 
487  static void removeRCPNode( RCPNode* rcp_node );
488 
497  template<class T>
498  static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
499  {
500 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
501  return getBaseObjVoidPtr(p);
502 #else
503  // This will not return the base address for polymorphic types if
504  // multiple inheritance and/or virtual bases are used but returning the
505  // static_cast should be okay in how it is used. It is just that the
506  // RCPNode tracing support will not always be able to figure out if two
507  // pointers of different type are pointing to the same object or not.
508  return static_cast<const void*>(p);
509 #endif
510  }
511 
518  static RCPNode* getExistingRCPNodeGivenLookupKey(
519  const void* lookupKey);
520 
527  template<class T>
529  {
530  return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
531  }
532 
534  static std::string getActiveRCPNodeHeaderString();
535 
537  static std::string getCommonDebugNotesString();
538 
540 
541 };
542 
543 
544 #ifdef TEUCHOS_DEBUG
545 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \
546  " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n"
547 #else
548 # define TEUCHOS_RCP_INSERION_NUMBER_STR()
549 #endif
550 
551 
557 template<class T, class Dealloc_T>
558 class RCPNodeTmpl : public RCPNode {
559 public:
561  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
562  : RCPNode(has_ownership_in), ptr_(p),
563 #ifdef TEUCHOS_DEBUG
564  base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
565  deleted_ptr_(0),
566 #endif
567  dealloc_(dealloc)
568  {}
570  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
571  : RCPNode(has_ownership_in), ptr_(p),
572 #ifdef TEUCHOS_DEBUG
573  base_obj_map_key_void_ptr_(0),
574  deleted_ptr_(0),
575 #endif
576  dealloc_(dealloc)
577  {}
579  Dealloc_T& get_nonconst_dealloc()
580  { return dealloc_; }
582  const Dealloc_T& get_dealloc() const
583  { return dealloc_; }
586  {
587 #ifdef TEUCHOS_DEBUG
589  "Error, the underlying object must be explicitly deleted before deleting"
590  " the node object!" );
591 #endif
592  }
594  virtual bool is_valid_ptr() const
595  {
596  return ptr_ != 0;
597  }
601  virtual void delete_obj()
602  {
603  if (ptr_!= 0) {
604  this->pre_delete_extra_data(); // Should not throw!
605  T* tmp_ptr = ptr_;
606 #ifdef TEUCHOS_DEBUG
607  deleted_ptr_ = tmp_ptr;
608 #endif
609  ptr_ = 0;
610  if (has_ownership()) {
611 #ifdef TEUCHOS_DEBUG
612  try {
613 #endif
614  dealloc_.free(tmp_ptr);
615 #ifdef TEUCHOS_DEBUG
616  }
617  TEUCHOS_CATCH_AND_ABORT
618 #endif
619  }
620  }
621  }
624  const std::string& rcp_type_name,
625  const void* rcp_ptr,
626  const RCPNode* rcp_node_ptr,
627  const void* rcp_obj_ptr
628  ) const
629  {
630  TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
631  const T* deleted_ptr =
632 #ifdef TEUCHOS_DEBUG
633  deleted_ptr_
634 #else
635  0
636 #endif
637  ;
638  TEUCHOS_ASSERT(rcp_node_ptr);
640  "Error, an attempt has been made to dereference the underlying object\n"
641  "from a weak smart pointer object where the underling object has already\n"
642  "been deleted since the strong count has already gone to zero.\n"
643  "\n"
644  "Context information:\n"
645  "\n"
646  " RCP type: " << rcp_type_name << "\n"
647  " RCP address: " << rcp_ptr << "\n"
648  " RCPNode type: " << typeName(*this) << "\n"
649  " RCPNode address: " << rcp_node_ptr << "\n"
650  TEUCHOS_RCP_INSERION_NUMBER_STR()
651  " RCP ptr address: " << rcp_obj_ptr << "\n"
652  " Concrete ptr address: " << deleted_ptr << "\n"
653  "\n"
655  );
656  // 2008/09/22: rabartl: Above, we do not provide the concreate object
657  // type or the concrete object address. In the case of the concrete
658  // object address, in a non-debug build, we don't want to pay a price
659  // for extra storage that we strictly don't need. In the case of the
660  // concrete object type name, we don't want to force non-debug built
661  // code to have the require that types be fully defined in order to use
662  // the memory management software. This is related to bug 4016.
663 
664  }
666  const std::string get_base_obj_type_name() const
667  {
668 #ifdef TEUCHOS_DEBUG
669  return TypeNameTraits<T>::name();
670 #else
671  return "UnknownType";
672 #endif
673  }
674 #ifdef TEUCHOS_DEBUG
675 
676  const void* get_base_obj_map_key_void_ptr() const
677  {
678  return base_obj_map_key_void_ptr_;
679  }
680 #endif
681 private:
682  T *ptr_;
683 #ifdef TEUCHOS_DEBUG
684  const void *base_obj_map_key_void_ptr_;
685  T *deleted_ptr_;
686 #endif
687  Dealloc_T dealloc_;
688  // not defined and not to be called
689  RCPNodeTmpl();
690  RCPNodeTmpl(const RCPNodeTmpl&);
691  RCPNodeTmpl& operator=(const RCPNodeTmpl&);
692 
693 }; // end class RCPNodeTmpl<T>
694 
695 
703 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
704 public:
710  void foo();
711 private:
712  static int count_;
713 };
714 
715 
716 } // namespace Teuchos
717 
718 
719 namespace {
720 // This static variable is declared before all other static variables that
721 // depend on RCP or other classes. Therefore, this static variable will be
722 // deleted *after* all of these other static variables that depend on RCP or
723 // created classes go away! This ensures that the node tracing machinery is
724 // setup and torn down correctly (this is the same trick used by the standard
725 // stream objects in many compiler implementations).
726 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
727 } // namespace (anonymous)
728 
729 
730 namespace Teuchos {
731 
748 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
749 public:
751  RCPNodeHandle (ENull null_arg = null)
752  : node_ (0), strength_ (RCP_STRONG)
753  {
754  (void) null_arg; // Silence "unused variable" compiler warning.
755  }
756 
759  ERCPStrength strength_in = RCP_STRONG,
760  bool newNode = true)
761  : node_ (node), strength_ (strength_in)
762  {
763 #ifdef TEUCHOS_DEBUG
764  TEUCHOS_ASSERT(node);
765 #endif // TEUCHOS_DEBUG
766 
767  bind();
768 
769 #ifdef TEUCHOS_DEBUG
770  // Add the node if this is the first RCPNodeHandle to get it. We have
771  // to add it because unbind() will call the remove_RCPNode(...) function
772  // and it needs to match when node tracing is on from the beginning.
773  if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) {
774  std::ostringstream os;
775  os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
776  << " has_ownership="<<node_->has_ownership()<<"}";
777  RCPNodeTracer::addNewRCPNode(node_, os.str());
778  }
779 #else
780  (void) newNode; // Silence "unused variable" compiler warning.
781 #endif // TEUCHOS_DEBUG
782  }
783 
784 #ifdef TEUCHOS_DEBUG
785 
786  template<typename T>
787  RCPNodeHandle (RCPNode* node, T *p, const std::string &T_name,
788  const std::string &ConcreteT_name,
789  const bool has_ownership_in,
790  ERCPStrength strength_in = RCP_STRONG)
791  : node_ (node), strength_ (strength_in)
792  {
793  TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
794  TEUCHOS_ASSERT(node_);
795  bind();
797  std::ostringstream os;
798  os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
799  <<", p="<<static_cast<const void*>(p)
800  <<", has_ownership="<<has_ownership_in<<"}";
801  RCPNodeTracer::addNewRCPNode(node_, os.str());
802  }
803  }
804 #endif // TEUCHOS_DEBUG
805 
807  RCPNodeHandle (const RCPNodeHandle& node_ref)
808  : node_ (node_ref.node_), strength_ (node_ref.strength_)
809  {
810  bind();
811  }
812 
814  void swap (RCPNodeHandle& node_ref) {
815  std::swap (node_ref.node_, node_);
816  std::swap (node_ref.strength_, strength_);
817  }
818 
824  RCPNodeHandle& operator= (const RCPNodeHandle& node_ref) {
825  // Assignment to self check: Note, We don't need to do an assigment to
826  // self check here because such a check is already done in the RCP and
827  // ArrayRCP classes.
828  // Take care of this's existing node and object
829  unbind(); // May throw in some cases
830  // Assign the new node
831  node_ = node_ref.node_;
832  strength_ = node_ref.strength_;
833  bind();
834  // Return
835  return *this;
836  }
837 
840  unbind();
841  }
842 
844  // otherwise return a null handle
846  // make weak handle
847  RCPNodeHandle possibleStrongNode(node_, RCP_WEAK, false);
848  if (possibleStrongNode.attemptConvertWeakToStrong()) {
849  return possibleStrongNode; // success - we have a good strong handle
850  }
851  return RCPNodeHandle(); // failure - return an empty handle
852  }
853 
856  if (node_) {
857  return RCPNodeHandle(node_, RCP_WEAK, false);
858  }
859  return RCPNodeHandle();
860  }
863  if (node_) {
864  return RCPNodeHandle(node_, RCP_STRONG, false);
865  }
866  return RCPNodeHandle();
867  }
869  RCPNode* node_ptr() const {
870  return node_;
871  }
873  bool is_node_null() const {
874  return node_==0;
875  }
879  bool is_valid_ptr() const {
880  if (node_) {
881  return node_->is_valid_ptr();
882  }
883  return true; // Null is a valid ptr!
884  }
887  bool same_node(const RCPNodeHandle &node2) const {
888  return node_ == node2.node_;
889  }
891  int strong_count() const {
892  if (node_) {
893  return node_->strong_count();
894  }
895  return 0;
896  }
898  int weak_count() const {
899  if (node_) {
900  return node_->weak_count(); // Not atomically safe
901  }
902  return 0;
903  }
905  int total_count() const {
906  if (node_) {
907  return node_->strong_count() + node_->weak_count(); // not atomically safe
908  }
909  return 0;
910  }
912  int count() const {
913  if (node_) {
914  return node_->strong_count();
915  }
916  return 0;
917  }
920  return strength_;
921  }
923  void has_ownership(bool has_ownership_in)
924  {
925  if (node_)
926  node_->has_ownership(has_ownership_in);
927  }
929  bool has_ownership() const
930  {
931  if (node_)
932  return node_->has_ownership();
933  return false;
934  }
937  const any &extra_data, const std::string& name,
938  EPrePostDestruction destroy_when, bool force_unique
939  )
940  {
941  debug_assert_not_null();
942  node_->set_extra_data(extra_data, name, destroy_when, force_unique);
943  }
945  any& get_extra_data( const std::string& type_name,
946  const std::string& name
947  )
948  {
949  debug_assert_not_null();
950  return node_->get_extra_data(type_name, name);
951  }
953  const any& get_extra_data( const std::string& type_name,
954  const std::string& name
955  ) const
956  {
957  return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
958  }
961  const std::string& type_name, const std::string& name
962  )
963  {
964  debug_assert_not_null();
965  return node_->get_optional_extra_data(type_name, name);
966  }
969  const std::string& type_name, const std::string& name
970  ) const
971  {
972  return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
973  }
976  {
977 #ifdef TEUCHOS_DEBUG
978  if (!node_)
979  throw_null_ptr_error(typeName(*this));
980 #endif
981  }
983  template<class RCPType>
984  void assert_valid_ptr(const RCPType& rcp_obj) const
985  {
986  if (!node_)
987  return; // Null is a valid pointer!
988  if (!is_valid_ptr()) {
989  node_->throw_invalid_obj_exception( typeName(rcp_obj),
990  this, node_, rcp_obj.access_private_ptr() );
991  }
992  }
994  template<class RCPType>
995  void debug_assert_valid_ptr(const RCPType& rcp_obj) const
996  {
997 #ifdef TEUCHOS_DEBUG
998  assert_valid_ptr(rcp_obj);
999 #endif
1000  }
1001 #ifdef TEUCHOS_DEBUG
1002  const void* get_base_obj_map_key_void_ptr() const
1003  {
1004  if (node_)
1005  return node_->get_base_obj_map_key_void_ptr();
1006  return 0;
1007  }
1008 #endif
1009 private:
1010  RCPNode *node_;
1011  ERCPStrength strength_;
1012  // atomically safe conversion of a weak handle to a strong handle if
1013  // possible - if not possible nothing changes
1014  bool attemptConvertWeakToStrong() {
1015  if (node_->attemptIncrementStrongCountFromNonZeroValue()) {
1016  // because we converted strong + 1 we account for this by doing weak - 1
1017  node_->deincr_count(RCP_WEAK);
1018  // we have successfully incremented the strong count by one
1019  strength_ = RCP_STRONG;
1020  return true;
1021  }
1022  return false;
1023  }
1024  inline void bind()
1025  {
1026  if (node_)
1027  node_->incr_count(strength_);
1028  }
1029  inline void unbind()
1030  {
1031  if (node_) {
1032  if(strength_ == RCP_STRONG) {
1033  // only strong checks for --strong == 0
1034  if (node_->deincr_count(RCP_STRONG) == 0) {
1035  unbindOneStrong();
1036  // but if strong hits 0 it also decrements weak_count_plus which
1037  // is weak + (strong != 0)
1038  if( node_->deincr_count(RCP_WEAK) == 0) {
1039  unbindOneTotal();
1040  }
1041  }
1042  }
1043  else if(node_->deincr_count(RCP_WEAK) == 0) { // weak checks here
1044  unbindOneTotal();
1045  }
1046  }
1047  }
1048 
1049  void unbindOneStrong();
1050  void unbindOneTotal();
1051 };
1052 
1053 
1058 inline
1059 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
1060 {
1061  // mfh 15 Sep 2015: Make sure that NULL pointers print consistently.
1062  // Clang 3.5 likes to print an empty string in that case, while GCC
1063  // prints 0. Thus, we test if the pointer is NULL and print 0 in
1064  // that case. This is important for MueLu tests, which compare
1065  // string print-outs.
1066  if (node.node_ptr () == NULL) {
1067  out << "0";
1068  } else {
1069  out << node.node_ptr ();
1070  }
1071  return out;
1072 }
1073 
1074 
1084 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
1085 public:
1088  : node_(node)
1089  {}
1096  {
1097  if (node_) {
1098  node_->has_ownership(false); // Avoid actually deleting ptr_
1099  node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
1100  delete node_;
1101  }
1102  }
1104  RCPNode* get() const
1105  {
1106  return node_;
1107  }
1109  void release()
1110  {
1111  node_ = 0;
1112  }
1113 private:
1114  RCPNode *node_;
1115  RCPNodeThrowDeleter(); // Not defined
1116  RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
1117  RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
1118 };
1119 
1120 
1121 //
1122 // Unit testing support
1123 //
1124 
1125 
1126 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1127 
1128 class SetTracingActiveNodesStack {
1129 public:
1130  SetTracingActiveNodesStack()
1131  {RCPNodeTracer::setTracingActiveRCPNodes(true);}
1132  ~SetTracingActiveNodesStack()
1133  {RCPNodeTracer::setTracingActiveRCPNodes(false);}
1134 };
1135 
1136 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
1137 
1138 #else
1139 
1140 # define SET_RCPNODE_TRACING() (void)0
1141 
1142 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1143 
1144 
1145 } // end namespace Teuchos
1146 
1147 
1148 #endif // TEUCHOS_RCP_NODE_HPP
Dangling reference error exception class.
const Dealloc_T & get_dealloc() const
bool has_ownership() const
int weak_count() const
The weak count for this RCPNode, or 0 if the node is NULL.
Modified boost::any class for holding a templated value.
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
virtual void throw_invalid_obj_exception(const std::string &rcp_type_name, const void *rcp_ptr, const RCPNode *rcp_node_ptr, const void *rcp_obj_ptr) const
static const void * getRCPNodeBaseObjMapKeyVoidPtr(T *p)
Get a const void* address to be used as the lookup key for an RCPNode given its embedded object&#39;s typ...
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Dealloc_T & get_nonconst_dealloc()
int deincr_count(const ERCPStrength strength)
any & get_extra_data(const std::string &type_name, const std::string &name)
void incr_count(const ERCPStrength strength)
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
RCPNodeHandle(ENull null_arg=null)
Default constructor.
void debug_assert_valid_ptr(const RCPType &rcp_obj) const
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
void release()
Releaes the RCPNode pointer before the destructor is called.
ENull
Used to initialize a RCP object to NULL using an implicit conversion!
const std::string get_base_obj_type_name() const
std::ostream & operator<<(std::ostream &out, const RCPNodeHandle &node)
Ouput stream operator for RCPNodeHandle.
Modified boost::any class, which is a container for a templated value.
RCPNodeHandle(const RCPNodeHandle &node_ref)
Copy constructor.
RCPNodeHandle(RCPNode *node, ERCPStrength strength_in=RCP_STRONG, bool newNode=true)
Constructor that takes a pointer to an RCPNode.
Sets up node tracing and prints remaining RCPNodes on destruction.
void has_ownership(bool has_ownership_in)
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
Debug-mode RCPNode tracing class.
virtual void delete_obj()
Delete the underlying object. Will abort if an exception is detected in the destructor.
Node class to keep track of address and the reference count for a reference-counted utility class and...
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in, ENull)
For undefined types .
RCPNodeHandle create_strong_lock() const
Return a strong handle if possible using thread safe atomics.
bool attemptIncrementStrongCountFromNonZeroValue()
attemptIncrementStrongCountFromNonZeroValue() supports weak to strong conversion but this is forward ...
Templated implementation class of RCPNode that has the responsibility for deleting the reference-coun...
#define TEUCHOS_TEST_FOR_EXCEPT_MSG(throw_exception_test, msg)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...
void assert_valid_ptr(const RCPType &rcp_obj) const
void debugAssertStrength(ERCPStrength strength)
RCPNodeHandle create_strong() const
Return a strong handle.
ERCPStrength strength() const
The strength of this handle.
int strong_count() const
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
ERCPStrength
Used to specify if the pointer is weak or strong.
const any & get_extra_data(const std::string &type_name, const std::string &name) const
RCPNode(bool has_ownership_in)
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
static RCPNode * getExistingRCPNode(T *p)
Return a raw pointer to an existing owning RCPNode given the address to the underlying object if it e...
void debug_assert_not_null() const
Provides std::map class for deficient platforms.
int weak_count() const
Handle class that manages the RCPNode&#39;s reference counting.
int strong_count() const
The strong count for this RCPNode, or 0 if the node is NULL.
void has_ownership(bool has_ownership_in)
#define TEUCHOS_TEST_FOR_TERMINATION(terminate_test, msg)
This macro is to be used instead of TEUCHOS_TEST_FOR_EXCEPTION() to report an error in situations whe...
ERCPNodeLookup
Used to determine if RCPNode lookup is performed or not.
~RCPNodeThrowDeleter()
Called with node_!=0 when an exception is thrown.
int total_count() const
The sum of the weak and string counts.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
bool is_valid_ptr() const
Whether the underlying pointer is valid.
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in)
For defined types.
This class creates a basic std::map object for platforms where the std::map is deficient, otherwise the std::map is injected into the Teuchos namespace.
bool same_node(const RCPNodeHandle &node2) const
Whether the RCPNode for which node2 is a handle is the same RCPNode as this object&#39;s RCPNode...
Deletes a (non-owning) RCPNode but not it&#39;s underlying object in case of a throw. ...
bool is_node_null() const
Whether the underlying RCPNode is NULL.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
const any & get_extra_data(const std::string &type_name, const std::string &name) const
RCPNode * node_ptr() const
Return a pointer to the underlying RCPNode.
Default traits class for converting objects into strings.
RCPNodeHandle create_weak() const
Return a weak handle.
virtual bool is_valid_ptr() const
int count() const
The strong count; retained for backwards compatibility.
Defines basic traits returning the name of a type in a portable and readable way. ...
void swap(RCPNodeHandle &node_ref)
Swap the contents of node_ref with *this.
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.