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 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef TEUCHOS_RCP_NODE_HPP
11 #define TEUCHOS_RCP_NODE_HPP
12 
13 
20 #include "Teuchos_ConfigDefs.hpp"
21 #include "Teuchos_any.hpp"
22 #include "Teuchos_map.hpp"
23 #include "Teuchos_ENull.hpp"
24 #include "Teuchos_Assert.hpp"
25 #include "Teuchos_Exceptions.hpp"
27 #include "Teuchos_toString.hpp"
28 #include "Teuchos_getBaseObjVoidPtr.hpp"
29 
30 #if defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE) && !defined(DISABLE_ATOMIC_COUNTERS)
31 #include <atomic>
32 #define USING_ATOMICS
33 #endif
34 
35 namespace Teuchos {
36 
37 #ifdef USING_ATOMICS
38 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) std::atomic<T> VAR
39 #else
40 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) T VAR
41 #endif
42 
47 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
48 
53 enum ERCPStrength { RCP_STRONG=0, RCP_WEAK=1 };
54 
59 enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP };
60 
62 inline void debugAssertStrength(ERCPStrength strength)
63 {
64 #ifdef TEUCHOS_DEBUG
65  switch (strength) {
66  case RCP_STRONG:
67  // fall through
68  case RCP_WEAK:
69  return; // Fine
70  default:
72  true, std::logic_error, "Teuchos::RCPNode: ERCPStrength enum value "
73  << strength << " is invalid (neither RCP_STRONG = " << RCP_STRONG
74  << " nor RCP_WEAK = " << RCP_WEAK << ").");
75  }
76 #else
77  (void) strength; // Silence "unused variable" compiler warning.
78 #endif // TEUCHOS_DEBUG
79 }
80 
86 template<>
87 class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
88 public:
89  static std::string toString( const ERCPStrength &t )
90  {
91  switch (t) {
92  case RCP_STRONG:
93  return "RCP_STRONG";
94  case RCP_WEAK:
95  return "RCP_WEAK";
96  default:
97  // Should never get here but fall through ...
98  break;
99  }
100  // Should never get here!
101 #ifdef TEUCHOS_DEBUG
103 #else
104  return "";
105 #endif
106  }
107 };
108 
109 
121 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
122 public:
124  RCPNode(bool has_ownership_in)
125  : has_ownership_(has_ownership_in), extra_data_map_(NULL)
126 #ifdef TEUCHOS_DEBUG
127  ,insertion_number_(-1)
128 #endif // TEUCHOS_DEBUG
129  {
130  count_[RCP_STRONG] = 0;
131  count_[RCP_WEAK] = 0;
132  }
134  virtual ~RCPNode()
135  {
136  if(extra_data_map_)
137  delete extra_data_map_;
138  }
143  {
144 #ifdef USING_ATOMICS
145  // this code follows the boost method
146  int strong_count_non_atomic = count_[RCP_STRONG];
147  for( ;; ) {
148  if (strong_count_non_atomic == 0) {
149  return false;
150  }
151  if (std::atomic_compare_exchange_weak( &count_[RCP_STRONG],
152  &strong_count_non_atomic, strong_count_non_atomic + 1)) {
153  return true;
154  }
155  }
156 #else
157  // the non-thread safe version - this fails with threads because
158  // strong_count_ can become 0 after the check if it is 0 and we would
159  // return true with no valid object
160  if (count_[RCP_STRONG] == 0) {
161  return false;
162  }
163  else {
164  ++count_[RCP_STRONG];
165  return true;
166  }
167 #endif
168  }
170  int strong_count() const
171  {
172  return count_[RCP_STRONG];
173  }
175  int weak_count() const // not atomically safe
176  {
177  return count_[RCP_WEAK] - (count_[RCP_STRONG] ? 1 : 0 ); // weak is +1 when strong > 0
178  }
180  void incr_count( const ERCPStrength strength )
181  {
182  debugAssertStrength(strength);
183  if (++count_[strength] == 1) {
184  if (strength == RCP_STRONG) {
185  ++count_[RCP_WEAK]; // this is the special condition - the first strong creates a weak
186  }
187  }
188  }
190  int deincr_count( const ERCPStrength strength )
191  {
192  debugAssertStrength(strength);
193 #ifdef BREAK_THREAD_SAFETY_OF_DEINCR_COUNT
194  --count_[strength];
195  return count_[strength]; // not atomically valid
196 #else
197  return --count_[strength];
198 #endif
199  }
201  void has_ownership(bool has_ownership_in)
202  {
203  has_ownership_ = has_ownership_in;
204  }
206  bool has_ownership() const
207  {
208  return has_ownership_;
209  }
211  void set_extra_data(
212  const any &extra_data, const std::string& name,
213  EPrePostDestruction destroy_when, bool force_unique );
215  any& get_extra_data( const std::string& type_name,
216  const std::string& name );
218  const any& get_extra_data( const std::string& type_name,
219  const std::string& name
220  ) const
221  {
222  return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
223  }
225  any* get_optional_extra_data(const std::string& type_name,
226  const std::string& name );
229  const std::string& type_name, const std::string& name
230  ) const
231  {
232  return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
233  }
235  virtual bool is_valid_ptr() const = 0;
237  virtual void delete_obj() = 0;
239  virtual void throw_invalid_obj_exception(
240  const std::string& rcp_type_name,
241  const void* rcp_ptr,
242  const RCPNode* rcp_node_ptr,
243  const void* rcp_obj_ptr
244  ) const = 0;
246  virtual const std::string get_base_obj_type_name() const = 0;
247 #ifdef TEUCHOS_DEBUG
248 
249  virtual const void* get_base_obj_map_key_void_ptr() const = 0;
250 #endif
251 protected:
254  {
255  if(extra_data_map_)
256  impl_pre_delete_extra_data();
257  }
258 private:
259  struct extra_data_entry_t {
260  extra_data_entry_t() : destroy_when(POST_DESTROY) {}
261  extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
262  : extra_data(_extra_data), destroy_when(_destroy_when)
263  {}
264  any extra_data;
265  EPrePostDestruction destroy_when;
266  };
267  typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
268 
269  TEUCHOS_RCP_DECL_ATOMIC(count_[2], int);
270  TEUCHOS_RCP_DECL_ATOMIC(has_ownership_, bool);
271 
272  extra_data_map_t *extra_data_map_;
273  // Above is made a pointer to reduce overhead for the general case when this
274  // is not used. However, this adds just a little bit to the overhead when
275  // it is used.
276  // Provides the "basic" guarantee!
277  void impl_pre_delete_extra_data();
278  // Not defined and not to be called
279  RCPNode();
280  RCPNode(const RCPNode&);
281  RCPNode& operator=(const RCPNode&);
282 #ifdef TEUCHOS_DEBUG
283  // removed atomic because mutex handles it - atomic would be redundant
284  int insertion_number_;
285 public:
286  void set_insertion_number(int insertion_number_in)
287  {
288  insertion_number_ = insertion_number_in;
289  }
290  int insertion_number() const
291  {
292  return insertion_number_;
293  }
294 #endif // TEUCHOS_DEBUG
295 };
296 
297 
302 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
303 
304 
305 #ifdef TEUCHOS_DEBUG
306  // to fully implement abort for TEUCHOS_STANDARD_CATCH_STATEMENTS in the cpp
308  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const std::exception &);
310  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const int &);
312  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor();
313  // called when RCPNode detects any exception in a destructor
314  #define TEUCHOS_CATCH_AND_ABORT \
315  catch(const std::exception &excpt) { abort_for_exception_in_destructor(excpt); } \
316  catch(const int &excpt_code) { abort_for_exception_in_destructor(excpt_code); } \
317  catch(...) { abort_for_exception_in_destructor(); }
318 #endif
319 
336 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
337 public:
338 
341 
345  : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
346  totalNumRCPNodeDeletions(0)
347  {}
348  long int maxNumRCPNodes;
349  long int totalNumRCPNodeAllocations;
350  long int totalNumRCPNodeDeletions;
351  };
352 
354 
357 
363  static bool isTracingActiveRCPNodes();
364 
365 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
366 
383  static void setTracingActiveRCPNodes(bool tracingActiveNodes);
384 #endif
385 
389  static int numActiveRCPNodes();
390 
392  static RCPNodeStatistics getRCPNodeStatistics() ;
393 
395  static void printRCPNodeStatistics(
396  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
397 
401  static void setPrintRCPNodeStatisticsOnExit(
402  bool printRCPNodeStatisticsOnExit);
403 
407  static bool getPrintRCPNodeStatisticsOnExit();
408 
412  static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit);
413 
417  static bool getPrintActiveRcpNodesOnExit();
418 
434  static void printActiveRCPNodes(std::ostream &out);
435 
437 
442 
447  static void addNewRCPNode(RCPNode* rcp_node,
448  const std::string &info );
449 
455  static void removeRCPNode( RCPNode* rcp_node );
456 
465  template<class T>
466  static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
467  {
468 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
469  return getBaseObjVoidPtr(p);
470 #else
471  // This will not return the base address for polymorphic types if
472  // multiple inheritance and/or virtual bases are used but returning the
473  // static_cast should be okay in how it is used. It is just that the
474  // RCPNode tracing support will not always be able to figure out if two
475  // pointers of different type are pointing to the same object or not.
476  return static_cast<const void*>(p);
477 #endif
478  }
479 
486  static RCPNode* getExistingRCPNodeGivenLookupKey(
487  const void* lookupKey);
488 
495  template<class T>
497  {
498  return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
499  }
500 
502  static std::string getActiveRCPNodeHeaderString();
503 
505  static std::string getCommonDebugNotesString();
506 
508 
509 };
510 
511 
512 #ifdef TEUCHOS_DEBUG
513 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \
514  " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n"
515 #else
516 # define TEUCHOS_RCP_INSERION_NUMBER_STR()
517 #endif
518 
519 
525 template<class T, class Dealloc_T>
526 class RCPNodeTmpl : public RCPNode {
527 public:
529  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
530  : RCPNode(has_ownership_in), ptr_(p),
531 #ifdef TEUCHOS_DEBUG
532  base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
533  deleted_ptr_(0),
534 #endif
535  dealloc_(dealloc)
536  {}
538  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
539  : RCPNode(has_ownership_in), ptr_(p),
540 #ifdef TEUCHOS_DEBUG
541  base_obj_map_key_void_ptr_(0),
542  deleted_ptr_(0),
543 #endif
544  dealloc_(dealloc)
545  {}
547  Dealloc_T& get_nonconst_dealloc()
548  { return dealloc_; }
550  const Dealloc_T& get_dealloc() const
551  { return dealloc_; }
554  {
555 #ifdef TEUCHOS_DEBUG
557  "Error, the underlying object must be explicitly deleted before deleting"
558  " the node object!" );
559 #endif
560  }
562  virtual bool is_valid_ptr() const
563  {
564  return ptr_ != 0;
565  }
569  virtual void delete_obj()
570  {
571  if (ptr_!= 0) {
572  this->pre_delete_extra_data(); // Should not throw!
573  T* tmp_ptr = ptr_;
574 #ifdef TEUCHOS_DEBUG
575  deleted_ptr_ = tmp_ptr;
576 #endif
577  ptr_ = 0;
578  if (has_ownership()) {
579 #ifdef TEUCHOS_DEBUG
580  try {
581 #endif
582  dealloc_.free(tmp_ptr);
583 #ifdef TEUCHOS_DEBUG
584  }
585  TEUCHOS_CATCH_AND_ABORT
586 #endif
587  }
588  }
589  }
592  const std::string& rcp_type_name,
593  const void* rcp_ptr,
594  const RCPNode* rcp_node_ptr,
595  const void* rcp_obj_ptr
596  ) const
597  {
598  TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
599  const T* deleted_ptr =
600 #ifdef TEUCHOS_DEBUG
601  deleted_ptr_
602 #else
603  0
604 #endif
605  ;
606  TEUCHOS_ASSERT(rcp_node_ptr);
608  "Error, an attempt has been made to dereference the underlying object\n"
609  "from a weak smart pointer object where the underling object has already\n"
610  "been deleted since the strong count has already gone to zero.\n"
611  "\n"
612  "Context information:\n"
613  "\n"
614  " RCP type: " << rcp_type_name << "\n"
615  " RCP address: " << rcp_ptr << "\n"
616  " RCPNode type: " << typeName(*this) << "\n"
617  " RCPNode address: " << rcp_node_ptr << "\n"
618  TEUCHOS_RCP_INSERION_NUMBER_STR()
619  " RCP ptr address: " << rcp_obj_ptr << "\n"
620  " Concrete ptr address: " << deleted_ptr << "\n"
621  "\n"
623  );
624  // 2008/09/22: rabartl: Above, we do not provide the concreate object
625  // type or the concrete object address. In the case of the concrete
626  // object address, in a non-debug build, we don't want to pay a price
627  // for extra storage that we strictly don't need. In the case of the
628  // concrete object type name, we don't want to force non-debug built
629  // code to have the require that types be fully defined in order to use
630  // the memory management software. This is related to bug 4016.
631 
632  }
634  const std::string get_base_obj_type_name() const
635  {
636 #ifdef TEUCHOS_DEBUG
637  return TypeNameTraits<T>::name();
638 #else
639  return "UnknownType";
640 #endif
641  }
642 #ifdef TEUCHOS_DEBUG
643 
644  const void* get_base_obj_map_key_void_ptr() const
645  {
646  return base_obj_map_key_void_ptr_;
647  }
648 #endif
649 private:
650  T *ptr_;
651 #ifdef TEUCHOS_DEBUG
652  const void *base_obj_map_key_void_ptr_;
653  T *deleted_ptr_;
654 #endif
655  Dealloc_T dealloc_;
656  // not defined and not to be called
657  RCPNodeTmpl();
658  RCPNodeTmpl(const RCPNodeTmpl&);
659  RCPNodeTmpl& operator=(const RCPNodeTmpl&);
660 
661 }; // end class RCPNodeTmpl<T>
662 
663 
671 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
672 public:
678  void foo();
679 private:
680  static int count_;
681 };
682 
683 
684 } // namespace Teuchos
685 
686 
687 namespace {
688 // This static variable is declared before all other static variables that
689 // depend on RCP or other classes. Therefore, this static variable will be
690 // deleted *after* all of these other static variables that depend on RCP or
691 // created classes go away! This ensures that the node tracing machinery is
692 // setup and torn down correctly (this is the same trick used by the standard
693 // stream objects in many compiler implementations).
694 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
695 } // namespace (anonymous)
696 
697 
698 namespace Teuchos {
699 
716 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
717 public:
719  RCPNodeHandle (ENull null_arg = null)
720  : node_ (0), strength_ (RCP_STRONG)
721  {
722  (void) null_arg; // Silence "unused variable" compiler warning.
723  }
724 
727  ERCPStrength strength_in = RCP_STRONG,
728  bool newNode = true)
729  : node_ (node), strength_ (strength_in)
730  {
731 #ifdef TEUCHOS_DEBUG
732  TEUCHOS_ASSERT(node);
733 #endif // TEUCHOS_DEBUG
734 
735  bind();
736 
737 #ifdef TEUCHOS_DEBUG
738  // Add the node if this is the first RCPNodeHandle to get it. We have
739  // to add it because unbind() will call the remove_RCPNode(...) function
740  // and it needs to match when node tracing is on from the beginning.
741  if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) {
742  std::ostringstream os;
743  os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
744  << " has_ownership="<<node_->has_ownership()<<"}";
745  RCPNodeTracer::addNewRCPNode(node_, os.str());
746  }
747 #else
748  (void) newNode; // Silence "unused variable" compiler warning.
749 #endif // TEUCHOS_DEBUG
750  }
751 
752 #ifdef TEUCHOS_DEBUG
753 
754  template<typename T>
755  RCPNodeHandle (RCPNode* node, T *p, const std::string &T_name,
756  const std::string &ConcreteT_name,
757  const bool has_ownership_in,
758  ERCPStrength strength_in = RCP_STRONG)
759  : node_ (node), strength_ (strength_in)
760  {
761  TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
762  TEUCHOS_ASSERT(node_);
763  bind();
765  std::ostringstream os;
766  os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
767  <<", p="<<static_cast<const void*>(p)
768  <<", has_ownership="<<has_ownership_in<<"}";
769  RCPNodeTracer::addNewRCPNode(node_, os.str());
770  }
771  }
772 #endif // TEUCHOS_DEBUG
773 
775  RCPNodeHandle (const RCPNodeHandle& node_ref)
776  : node_ (node_ref.node_), strength_ (node_ref.strength_)
777  {
778  bind();
779  }
780 
783  : node_ (node_ref.node_), strength_ (node_ref.strength_)
784  {
785  node_ref.node_ = 0;
786  node_ref.strength_ = RCP_STRONG;
787  }
788 
790  void swap (RCPNodeHandle& node_ref) {
791  std::swap (node_ref.node_, node_);
792  std::swap (node_ref.strength_, strength_);
793  }
794 
795 
796 
802  RCPNodeHandle& operator= (ENull) {
803  unbind(); // May throw in some cases
804  node_ = 0;
805  strength_ = RCP_STRONG;
806  return *this;
807  }
808 
814  RCPNodeHandle& operator= (const RCPNodeHandle& node_ref) {
815  // NOTE: Don't need to check assignment to self since user-facing classes
816  // do that!
817  unbind(); // May throw in some cases
818  node_ = node_ref.node_;
819  strength_ = node_ref.strength_;
820  bind();
821  return *this;
822  }
823 
829  RCPNodeHandle& operator= (RCPNodeHandle&& node_ref) {
830  // NOTE: Don't need to check assignment to self since user-facing classes
831  // do that!
832  unbind(); // May throw in some cases
833  node_ = node_ref.node_;
834  strength_ = node_ref.strength_;
835  node_ref.node_ = 0;
836  node_ref.strength_ = RCP_STRONG;
837  return *this;
838  }
839 
842  unbind();
843  }
844 
846  // otherwise return a null handle
848  // make weak handle
849  RCPNodeHandle possibleStrongNode(node_, RCP_WEAK, false);
850  if (possibleStrongNode.attemptConvertWeakToStrong()) {
851  return possibleStrongNode; // success - we have a good strong handle
852  }
853  return RCPNodeHandle(); // failure - return an empty handle
854  }
855 
858  if (node_) {
859  return RCPNodeHandle(node_, RCP_WEAK, false);
860  }
861  return RCPNodeHandle();
862  }
865  if (node_) {
866  return RCPNodeHandle(node_, RCP_STRONG, false);
867  }
868  return RCPNodeHandle();
869  }
871  RCPNode* node_ptr() const {
872  return node_;
873  }
875  bool is_node_null() const {
876  return node_==0;
877  }
881  bool is_valid_ptr() const {
882  if (node_) {
883  return node_->is_valid_ptr();
884  }
885  return true; // Null is a valid ptr!
886  }
889  bool same_node(const RCPNodeHandle &node2) const {
890  return node_ == node2.node_;
891  }
893  int strong_count() const {
894  if (node_) {
895  return node_->strong_count();
896  }
897  return 0;
898  }
900  int weak_count() const {
901  if (node_) {
902  return node_->weak_count(); // Not atomically safe
903  }
904  return 0;
905  }
907  int total_count() const {
908  if (node_) {
909  return node_->strong_count() + node_->weak_count(); // not atomically safe
910  }
911  return 0;
912  }
915  return strength_;
916  }
918  void has_ownership(bool has_ownership_in)
919  {
920  if (node_)
921  node_->has_ownership(has_ownership_in);
922  }
924  bool has_ownership() const
925  {
926  if (node_)
927  return node_->has_ownership();
928  return false;
929  }
932  const any &extra_data, const std::string& name,
933  EPrePostDestruction destroy_when, bool force_unique
934  )
935  {
936  debug_assert_not_null();
937  node_->set_extra_data(extra_data, name, destroy_when, force_unique);
938  }
940  any& get_extra_data( const std::string& type_name,
941  const std::string& name
942  )
943  {
944  debug_assert_not_null();
945  return node_->get_extra_data(type_name, name);
946  }
948  const any& get_extra_data( const std::string& type_name,
949  const std::string& name
950  ) const
951  {
952  return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
953  }
956  const std::string& type_name, const std::string& name
957  )
958  {
959  debug_assert_not_null();
960  return node_->get_optional_extra_data(type_name, name);
961  }
964  const std::string& type_name, const std::string& name
965  ) const
966  {
967  return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
968  }
971  {
972 #ifdef TEUCHOS_DEBUG
973  if (!node_)
974  throw_null_ptr_error(typeName(*this));
975 #endif
976  }
978  template<class RCPType>
979  void assert_valid_ptr(const RCPType& rcp_obj) const
980  {
981  if (!node_)
982  return; // Null is a valid pointer!
983  if (!is_valid_ptr()) {
984  node_->throw_invalid_obj_exception( typeName(rcp_obj),
985  this, node_, rcp_obj.access_private_ptr() );
986  }
987  }
989  template<class RCPType>
990  void debug_assert_valid_ptr(const RCPType& rcp_obj) const
991  {
992 #ifdef TEUCHOS_DEBUG
993  assert_valid_ptr(rcp_obj);
994 #endif
995  }
996 #ifdef TEUCHOS_DEBUG
997  const void* get_base_obj_map_key_void_ptr() const
998  {
999  if (node_)
1000  return node_->get_base_obj_map_key_void_ptr();
1001  return 0;
1002  }
1003 #endif
1004 private:
1005  RCPNode *node_;
1006  ERCPStrength strength_;
1007  // atomically safe conversion of a weak handle to a strong handle if
1008  // possible - if not possible nothing changes
1009  bool attemptConvertWeakToStrong() {
1010  if (node_->attemptIncrementStrongCountFromNonZeroValue()) {
1011  // because we converted strong + 1 we account for this by doing weak - 1
1012  node_->deincr_count(RCP_WEAK);
1013  // we have successfully incremented the strong count by one
1014  strength_ = RCP_STRONG;
1015  return true;
1016  }
1017  return false;
1018  }
1019  inline void bind()
1020  {
1021  if (node_)
1022  node_->incr_count(strength_);
1023  }
1024  inline void unbind()
1025  {
1026  if (node_) {
1027  if(strength_ == RCP_STRONG) {
1028  // only strong checks for --strong == 0
1029  if (node_->deincr_count(RCP_STRONG) == 0) {
1030  unbindOneStrong();
1031  // but if strong hits 0 it also decrements weak_count_plus which
1032  // is weak + (strong != 0)
1033  if( node_->deincr_count(RCP_WEAK) == 0) {
1034  unbindOneTotal();
1035  }
1036  }
1037  }
1038  else if(node_->deincr_count(RCP_WEAK) == 0) { // weak checks here
1039  unbindOneTotal();
1040  }
1041  }
1042  }
1043  void unbindOneStrong();
1044  void unbindOneTotal();
1045 };
1046 
1047 
1052 inline
1053 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
1054 {
1055  // mfh 15 Sep 2015: Make sure that NULL pointers print consistently.
1056  // Clang 3.5 likes to print an empty string in that case, while GCC
1057  // prints 0. Thus, we test if the pointer is NULL and print 0 in
1058  // that case. This is important for MueLu tests, which compare
1059  // string print-outs.
1060  if (node.node_ptr () == NULL) {
1061  out << "0";
1062  } else {
1063  out << node.node_ptr ();
1064  }
1065  return out;
1066 }
1067 
1068 
1078 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
1079 public:
1082  : node_(node)
1083  {}
1090  {
1091  if (node_) {
1092  node_->has_ownership(false); // Avoid actually deleting ptr_
1093  node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
1094  delete node_;
1095  }
1096  }
1098  RCPNode* get() const
1099  {
1100  return node_;
1101  }
1103  void release()
1104  {
1105  node_ = 0;
1106  }
1107 private:
1108  RCPNode *node_;
1109  RCPNodeThrowDeleter(); // Not defined
1110  RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
1111  RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
1112 };
1113 
1114 
1115 //
1116 // Unit testing support
1117 //
1118 
1119 
1120 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1121 
1122 class SetTracingActiveNodesStack {
1123 public:
1124  SetTracingActiveNodesStack()
1125  {RCPNodeTracer::setTracingActiveRCPNodes(true);}
1126  ~SetTracingActiveNodesStack()
1127  {RCPNodeTracer::setTracingActiveRCPNodes(false);}
1128 };
1129 
1130 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
1131 
1132 #else
1133 
1134 # define SET_RCPNODE_TRACING() (void)0
1135 
1136 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1137 
1138 
1139 } // end namespace Teuchos
1140 
1141 
1142 #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
RCPNodeHandle(RCPNodeHandle &&node_ref)
Move constructor.
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
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.