Teuchos - Trilinos Tools Package  Version of the Day
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  return "";
136 #else
137  return "";
138 #endif
139  }
140 };
141 
142 
154 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
155 public:
157  RCPNode(bool has_ownership_in)
158  : has_ownership_(has_ownership_in), extra_data_map_(NULL)
159 #ifdef TEUCHOS_DEBUG
160  ,insertion_number_(-1)
161 #endif // TEUCHOS_DEBUG
162  {
163  count_[RCP_STRONG] = 0;
164  count_[RCP_WEAK] = 0;
165  }
167  virtual ~RCPNode()
168  {
169  if(extra_data_map_)
170  delete extra_data_map_;
171  }
176  {
177 #ifdef USING_ATOMICS
178  // this code follows the boost method
179  int strong_count_non_atomic = count_[RCP_STRONG];
180  for( ;; ) {
181  if (strong_count_non_atomic == 0) {
182  return false;
183  }
184  if (std::atomic_compare_exchange_weak( &count_[RCP_STRONG],
185  &strong_count_non_atomic, strong_count_non_atomic + 1)) {
186  return true;
187  }
188  }
189 #else
190  // the non-thread safe version - this fails with threads because
191  // strong_count_ can become 0 after the check if it is 0 and we would
192  // return true with no valid object
193  if (count_[RCP_STRONG] == 0) {
194  return false;
195  }
196  else {
197  ++count_[RCP_STRONG];
198  return true;
199  }
200 #endif
201  }
203  int strong_count() const
204  {
205  return count_[RCP_STRONG];
206  }
208  int weak_count() const // not atomically safe
209  {
210  return count_[RCP_WEAK] - (count_[RCP_STRONG] ? 1 : 0 ); // weak is +1 when strong > 0
211  }
213  void incr_count( const ERCPStrength strength )
214  {
215  debugAssertStrength(strength);
216  if (++count_[strength] == 1) {
217  if (strength == RCP_STRONG) {
218  ++count_[RCP_WEAK]; // this is the special condition - the first strong creates a weak
219  }
220  }
221  }
223  int deincr_count( const ERCPStrength strength )
224  {
225  debugAssertStrength(strength);
226 #ifdef BREAK_THREAD_SAFETY_OF_DEINCR_COUNT
227  --count_[strength];
228  return count_[strength]; // not atomically valid
229 #else
230  return --count_[strength];
231 #endif
232  }
234  void has_ownership(bool has_ownership_in)
235  {
236  has_ownership_ = has_ownership_in;
237  }
239  bool has_ownership() const
240  {
241  return has_ownership_;
242  }
244  void set_extra_data(
245  const any &extra_data, const std::string& name,
246  EPrePostDestruction destroy_when, bool force_unique );
248  any& get_extra_data( const std::string& type_name,
249  const std::string& name );
251  const any& get_extra_data( const std::string& type_name,
252  const std::string& name
253  ) const
254  {
255  return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
256  }
258  any* get_optional_extra_data(const std::string& type_name,
259  const std::string& name );
262  const std::string& type_name, const std::string& name
263  ) const
264  {
265  return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
266  }
268  virtual bool is_valid_ptr() const = 0;
270  virtual void delete_obj() = 0;
272  virtual void throw_invalid_obj_exception(
273  const std::string& rcp_type_name,
274  const void* rcp_ptr,
275  const RCPNode* rcp_node_ptr,
276  const void* rcp_obj_ptr
277  ) const = 0;
279  virtual const std::string get_base_obj_type_name() const = 0;
280 #ifdef TEUCHOS_DEBUG
281 
282  virtual const void* get_base_obj_map_key_void_ptr() const = 0;
283 #endif
284 protected:
287  {
288  if(extra_data_map_)
289  impl_pre_delete_extra_data();
290  }
291 private:
292  struct extra_data_entry_t {
293  extra_data_entry_t() : destroy_when(POST_DESTROY) {}
294  extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
295  : extra_data(_extra_data), destroy_when(_destroy_when)
296  {}
297  any extra_data;
298  EPrePostDestruction destroy_when;
299  };
300  typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
301 
302  TEUCHOS_RCP_DECL_ATOMIC(count_[2], int);
303  TEUCHOS_RCP_DECL_ATOMIC(has_ownership_, bool);
304 
305  extra_data_map_t *extra_data_map_;
306  // Above is made a pointer to reduce overhead for the general case when this
307  // is not used. However, this adds just a little bit to the overhead when
308  // it is used.
309  // Provides the "basic" guarantee!
310  void impl_pre_delete_extra_data();
311  // Not defined and not to be called
312  RCPNode();
313  RCPNode(const RCPNode&);
314  RCPNode& operator=(const RCPNode&);
315 #ifdef TEUCHOS_DEBUG
316  // removed atomic because mutex handles it - atomic would be redundant
317  int insertion_number_;
318 public:
319  void set_insertion_number(int insertion_number_in)
320  {
321  insertion_number_ = insertion_number_in;
322  }
323  int insertion_number() const
324  {
325  return insertion_number_;
326  }
327 #endif // TEUCHOS_DEBUG
328 };
329 
330 
335 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
336 
337 
338 #ifdef TEUCHOS_DEBUG
339  // to fully implement abort for TEUCHOS_STANDARD_CATCH_STATEMENTS in the cpp
341  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const std::exception &);
343  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const int &);
345  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor();
346  // called when RCPNode detects any exception in a destructor
347  #define TEUCHOS_CATCH_AND_ABORT \
348  catch(const std::exception &excpt) { abort_for_exception_in_destructor(excpt); } \
349  catch(const int &excpt_code) { abort_for_exception_in_destructor(excpt_code); } \
350  catch(...) { abort_for_exception_in_destructor(); }
351 #endif
352 
369 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
370 public:
371 
374 
378  : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
379  totalNumRCPNodeDeletions(0)
380  {}
381  long int maxNumRCPNodes;
382  long int totalNumRCPNodeAllocations;
383  long int totalNumRCPNodeDeletions;
384  };
385 
387 
390 
396  static bool isTracingActiveRCPNodes();
397 
398 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
399 
416  static void setTracingActiveRCPNodes(bool tracingActiveNodes);
417 #endif
418 
422  static int numActiveRCPNodes();
423 
425  static RCPNodeStatistics getRCPNodeStatistics() ;
426 
428  static void printRCPNodeStatistics(
429  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
430 
434  static void setPrintRCPNodeStatisticsOnExit(
435  bool printRCPNodeStatisticsOnExit);
436 
440  static bool getPrintRCPNodeStatisticsOnExit();
441 
445  static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit);
446 
450  static bool getPrintActiveRcpNodesOnExit();
451 
467  static void printActiveRCPNodes(std::ostream &out);
468 
470 
475 
480  static void addNewRCPNode(RCPNode* rcp_node,
481  const std::string &info );
482 
488  static void removeRCPNode( RCPNode* rcp_node );
489 
498  template<class T>
499  static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
500  {
501 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
502  return getBaseObjVoidPtr(p);
503 #else
504  // This will not return the base address for polymorphic types if
505  // multiple inheritance and/or virtual bases are used but returning the
506  // static_cast should be okay in how it is used. It is just that the
507  // RCPNode tracing support will not always be able to figure out if two
508  // pointers of different type are pointing to the same object or not.
509  return static_cast<const void*>(p);
510 #endif
511  }
512 
519  static RCPNode* getExistingRCPNodeGivenLookupKey(
520  const void* lookupKey);
521 
528  template<class T>
530  {
531  return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
532  }
533 
535  static std::string getActiveRCPNodeHeaderString();
536 
538  static std::string getCommonDebugNotesString();
539 
541 
542 };
543 
544 
545 #ifdef TEUCHOS_DEBUG
546 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \
547  " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n"
548 #else
549 # define TEUCHOS_RCP_INSERION_NUMBER_STR()
550 #endif
551 
552 
558 template<class T, class Dealloc_T>
559 class RCPNodeTmpl : public RCPNode {
560 public:
562  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
563  : RCPNode(has_ownership_in), ptr_(p),
564 #ifdef TEUCHOS_DEBUG
565  base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
566  deleted_ptr_(0),
567 #endif
568  dealloc_(dealloc)
569  {}
571  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
572  : RCPNode(has_ownership_in), ptr_(p),
573 #ifdef TEUCHOS_DEBUG
574  base_obj_map_key_void_ptr_(0),
575  deleted_ptr_(0),
576 #endif
577  dealloc_(dealloc)
578  {}
580  Dealloc_T& get_nonconst_dealloc()
581  { return dealloc_; }
583  const Dealloc_T& get_dealloc() const
584  { return dealloc_; }
587  {
588 #ifdef TEUCHOS_DEBUG
590  "Error, the underlying object must be explicitly deleted before deleting"
591  " the node object!" );
592 #endif
593  }
595  virtual bool is_valid_ptr() const
596  {
597  return ptr_ != 0;
598  }
602  virtual void delete_obj()
603  {
604  if (ptr_!= 0) {
605  this->pre_delete_extra_data(); // Should not throw!
606  T* tmp_ptr = ptr_;
607 #ifdef TEUCHOS_DEBUG
608  deleted_ptr_ = tmp_ptr;
609 #endif
610  ptr_ = 0;
611  if (has_ownership()) {
612 #ifdef TEUCHOS_DEBUG
613  try {
614 #endif
615  dealloc_.free(tmp_ptr);
616 #ifdef TEUCHOS_DEBUG
617  }
618  TEUCHOS_CATCH_AND_ABORT
619 #endif
620  }
621  }
622  }
625  const std::string& rcp_type_name,
626  const void* rcp_ptr,
627  const RCPNode* rcp_node_ptr,
628  const void* rcp_obj_ptr
629  ) const
630  {
631  TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
632  const T* deleted_ptr =
633 #ifdef TEUCHOS_DEBUG
634  deleted_ptr_
635 #else
636  0
637 #endif
638  ;
639  TEUCHOS_ASSERT(rcp_node_ptr);
641  "Error, an attempt has been made to dereference the underlying object\n"
642  "from a weak smart pointer object where the underling object has already\n"
643  "been deleted since the strong count has already gone to zero.\n"
644  "\n"
645  "Context information:\n"
646  "\n"
647  " RCP type: " << rcp_type_name << "\n"
648  " RCP address: " << rcp_ptr << "\n"
649  " RCPNode type: " << typeName(*this) << "\n"
650  " RCPNode address: " << rcp_node_ptr << "\n"
651  TEUCHOS_RCP_INSERION_NUMBER_STR()
652  " RCP ptr address: " << rcp_obj_ptr << "\n"
653  " Concrete ptr address: " << deleted_ptr << "\n"
654  "\n"
656  );
657  // 2008/09/22: rabartl: Above, we do not provide the concreate object
658  // type or the concrete object address. In the case of the concrete
659  // object address, in a non-debug build, we don't want to pay a price
660  // for extra storage that we strictly don't need. In the case of the
661  // concrete object type name, we don't want to force non-debug built
662  // code to have the require that types be fully defined in order to use
663  // the memory management software. This is related to bug 4016.
664 
665  }
667  const std::string get_base_obj_type_name() const
668  {
669 #ifdef TEUCHOS_DEBUG
670  return TypeNameTraits<T>::name();
671 #else
672  return "UnknownType";
673 #endif
674  }
675 #ifdef TEUCHOS_DEBUG
676 
677  const void* get_base_obj_map_key_void_ptr() const
678  {
679  return base_obj_map_key_void_ptr_;
680  }
681 #endif
682 private:
683  T *ptr_;
684 #ifdef TEUCHOS_DEBUG
685  const void *base_obj_map_key_void_ptr_;
686  T *deleted_ptr_;
687 #endif
688  Dealloc_T dealloc_;
689  // not defined and not to be called
690  RCPNodeTmpl();
691  RCPNodeTmpl(const RCPNodeTmpl&);
692  RCPNodeTmpl& operator=(const RCPNodeTmpl&);
693 
694 }; // end class RCPNodeTmpl<T>
695 
696 
704 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
705 public:
711  void foo();
712 private:
713  static int count_;
714 };
715 
716 
717 } // namespace Teuchos
718 
719 
720 namespace {
721 // This static variable is declared before all other static variables that
722 // depend on RCP or other classes. Therefore, this static variable will be
723 // deleted *after* all of these other static variables that depend on RCP or
724 // created classes go away! This ensures that the node tracing machinery is
725 // setup and torn down correctly (this is the same trick used by the standard
726 // stream objects in many compiler implementations).
727 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
728 } // namespace (anonymous)
729 
730 
731 namespace Teuchos {
732 
749 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
750 public:
752  RCPNodeHandle (ENull null_arg = null)
753  : node_ (0), strength_ (RCP_STRONG)
754  {
755  (void) null_arg; // Silence "unused variable" compiler warning.
756  }
757 
760  ERCPStrength strength_in = RCP_STRONG,
761  bool newNode = true)
762  : node_ (node), strength_ (strength_in)
763  {
764 #ifdef TEUCHOS_DEBUG
765  TEUCHOS_ASSERT(node);
766 #endif // TEUCHOS_DEBUG
767 
768  bind();
769 
770 #ifdef TEUCHOS_DEBUG
771  // Add the node if this is the first RCPNodeHandle to get it. We have
772  // to add it because unbind() will call the remove_RCPNode(...) function
773  // and it needs to match when node tracing is on from the beginning.
774  if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) {
775  std::ostringstream os;
776  os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
777  << " has_ownership="<<node_->has_ownership()<<"}";
778  RCPNodeTracer::addNewRCPNode(node_, os.str());
779  }
780 #else
781  (void) newNode; // Silence "unused variable" compiler warning.
782 #endif // TEUCHOS_DEBUG
783  }
784 
785 #ifdef TEUCHOS_DEBUG
786 
787  template<typename T>
788  RCPNodeHandle (RCPNode* node, T *p, const std::string &T_name,
789  const std::string &ConcreteT_name,
790  const bool has_ownership_in,
791  ERCPStrength strength_in = RCP_STRONG)
792  : node_ (node), strength_ (strength_in)
793  {
794  TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
795  TEUCHOS_ASSERT(node_);
796  bind();
798  std::ostringstream os;
799  os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
800  <<", p="<<static_cast<const void*>(p)
801  <<", has_ownership="<<has_ownership_in<<"}";
802  RCPNodeTracer::addNewRCPNode(node_, os.str());
803  }
804  }
805 #endif // TEUCHOS_DEBUG
806 
808  RCPNodeHandle (const RCPNodeHandle& node_ref)
809  : node_ (node_ref.node_), strength_ (node_ref.strength_)
810  {
811  bind();
812  }
813 
815  void swap (RCPNodeHandle& node_ref) {
816  std::swap (node_ref.node_, node_);
817  std::swap (node_ref.strength_, strength_);
818  }
819 
825  RCPNodeHandle& operator= (const RCPNodeHandle& node_ref) {
826  // Assignment to self check: Note, We don't need to do an assigment to
827  // self check here because such a check is already done in the RCP and
828  // ArrayRCP classes.
829  // Take care of this's existing node and object
830  unbind(); // May throw in some cases
831  // Assign the new node
832  node_ = node_ref.node_;
833  strength_ = node_ref.strength_;
834  bind();
835  // Return
836  return *this;
837  }
838 
841  unbind();
842  }
843 
845  // otherwise return a null handle
847  // make weak handle
848  RCPNodeHandle possibleStrongNode(node_, RCP_WEAK, false);
849  if (possibleStrongNode.attemptConvertWeakToStrong()) {
850  return possibleStrongNode; // success - we have a good strong handle
851  }
852  return RCPNodeHandle(); // failure - return an empty handle
853  }
854 
857  if (node_) {
858  return RCPNodeHandle(node_, RCP_WEAK, false);
859  }
860  return RCPNodeHandle();
861  }
864  if (node_) {
865  return RCPNodeHandle(node_, RCP_STRONG, false);
866  }
867  return RCPNodeHandle();
868  }
870  RCPNode* node_ptr() const {
871  return node_;
872  }
874  bool is_node_null() const {
875  return node_==0;
876  }
880  bool is_valid_ptr() const {
881  if (node_) {
882  return node_->is_valid_ptr();
883  }
884  return true; // Null is a valid ptr!
885  }
888  bool same_node(const RCPNodeHandle &node2) const {
889  return node_ == node2.node_;
890  }
892  int strong_count() const {
893  if (node_) {
894  return node_->strong_count();
895  }
896  return 0;
897  }
899  int weak_count() const {
900  if (node_) {
901  return node_->weak_count(); // Not atomically safe
902  }
903  return 0;
904  }
906  int total_count() const {
907  if (node_) {
908  return node_->strong_count() + node_->weak_count(); // not atomically safe
909  }
910  return 0;
911  }
913  int count() const {
914  if (node_) {
915  return node_->strong_count();
916  }
917  return 0;
918  }
921  return strength_;
922  }
924  void has_ownership(bool has_ownership_in)
925  {
926  if (node_)
927  node_->has_ownership(has_ownership_in);
928  }
930  bool has_ownership() const
931  {
932  if (node_)
933  return node_->has_ownership();
934  return false;
935  }
938  const any &extra_data, const std::string& name,
939  EPrePostDestruction destroy_when, bool force_unique
940  )
941  {
942  debug_assert_not_null();
943  node_->set_extra_data(extra_data, name, destroy_when, force_unique);
944  }
946  any& get_extra_data( const std::string& type_name,
947  const std::string& name
948  )
949  {
950  debug_assert_not_null();
951  return node_->get_extra_data(type_name, name);
952  }
954  const any& get_extra_data( const std::string& type_name,
955  const std::string& name
956  ) const
957  {
958  return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
959  }
962  const std::string& type_name, const std::string& name
963  )
964  {
965  debug_assert_not_null();
966  return node_->get_optional_extra_data(type_name, name);
967  }
970  const std::string& type_name, const std::string& name
971  ) const
972  {
973  return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
974  }
977  {
978 #ifdef TEUCHOS_DEBUG
979  if (!node_)
980  throw_null_ptr_error(typeName(*this));
981 #endif
982  }
984  template<class RCPType>
985  void assert_valid_ptr(const RCPType& rcp_obj) const
986  {
987  if (!node_)
988  return; // Null is a valid pointer!
989  if (!is_valid_ptr()) {
990  node_->throw_invalid_obj_exception( typeName(rcp_obj),
991  this, node_, rcp_obj.access_private_ptr() );
992  }
993  }
995  template<class RCPType>
996  void debug_assert_valid_ptr(const RCPType& rcp_obj) const
997  {
998 #ifdef TEUCHOS_DEBUG
999  assert_valid_ptr(rcp_obj);
1000 #endif
1001  }
1002 #ifdef TEUCHOS_DEBUG
1003  const void* get_base_obj_map_key_void_ptr() const
1004  {
1005  if (node_)
1006  return node_->get_base_obj_map_key_void_ptr();
1007  return 0;
1008  }
1009 #endif
1010 private:
1011  RCPNode *node_;
1012  ERCPStrength strength_;
1013  // atomically safe conversion of a weak handle to a strong handle if
1014  // possible - if not possible nothing changes
1015  bool attemptConvertWeakToStrong() {
1016  if (node_->attemptIncrementStrongCountFromNonZeroValue()) {
1017  // because we converted strong + 1 we account for this by doing weak - 1
1018  node_->deincr_count(RCP_WEAK);
1019  // we have successfully incremented the strong count by one
1020  strength_ = RCP_STRONG;
1021  return true;
1022  }
1023  return false;
1024  }
1025  inline void bind()
1026  {
1027  if (node_)
1028  node_->incr_count(strength_);
1029  }
1030  inline void unbind()
1031  {
1032  if (node_) {
1033  if(strength_ == RCP_STRONG) {
1034  // only strong checks for --strong == 0
1035  if (node_->deincr_count(RCP_STRONG) == 0) {
1036  unbindOneStrong();
1037  // but if strong hits 0 it also decrements weak_count_plus which
1038  // is weak + (strong != 0)
1039  if( node_->deincr_count(RCP_WEAK) == 0) {
1040  unbindOneTotal();
1041  }
1042  }
1043  }
1044  else if(node_->deincr_count(RCP_WEAK) == 0) { // weak checks here
1045  unbindOneTotal();
1046  }
1047  }
1048  }
1049 
1050  void unbindOneStrong();
1051  void unbindOneTotal();
1052 };
1053 
1054 
1059 inline
1060 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
1061 {
1062  // mfh 15 Sep 2015: Make sure that NULL pointers print consistently.
1063  // Clang 3.5 likes to print an empty string in that case, while GCC
1064  // prints 0. Thus, we test if the pointer is NULL and print 0 in
1065  // that case. This is important for MueLu tests, which compare
1066  // string print-outs.
1067  if (node.node_ptr () == NULL) {
1068  out << "0";
1069  } else {
1070  out << node.node_ptr ();
1071  }
1072  return out;
1073 }
1074 
1075 
1085 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
1086 public:
1089  : node_(node)
1090  {}
1097  {
1098  if (node_) {
1099  node_->has_ownership(false); // Avoid actually deleting ptr_
1100  node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
1101  delete node_;
1102  }
1103  }
1105  RCPNode* get() const
1106  {
1107  return node_;
1108  }
1110  void release()
1111  {
1112  node_ = 0;
1113  }
1114 private:
1115  RCPNode *node_;
1116  RCPNodeThrowDeleter(); // Not defined
1117  RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
1118  RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
1119 };
1120 
1121 
1122 //
1123 // Unit testing support
1124 //
1125 
1126 
1127 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1128 
1129 class SetTracingActiveNodesStack {
1130 public:
1131  SetTracingActiveNodesStack()
1132  {RCPNodeTracer::setTracingActiveRCPNodes(true);}
1133  ~SetTracingActiveNodesStack()
1134  {RCPNodeTracer::setTracingActiveRCPNodes(false);}
1135 };
1136 
1137 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
1138 
1139 #else
1140 
1141 # define SET_RCPNODE_TRACING() (void)0
1142 
1143 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1144 
1145 
1146 } // end namespace Teuchos
1147 
1148 
1149 #endif // TEUCHOS_RCP_NODE_HPP
Teuchos::TypeNameTraits::name
static std::string name()
Definition: Teuchos_TypeNameTraits.hpp:88
Teuchos::RCPNodeHandle::has_ownership
void has_ownership(bool has_ownership_in)
Definition: Teuchos_RCPNode.hpp:924
Teuchos::RCPNodeHandle::count
int count() const
The strong count; retained for backwards compatibility.
Definition: Teuchos_RCPNode.hpp:913
Teuchos::RCPNodeHandle::debug_assert_not_null
void debug_assert_not_null() const
Definition: Teuchos_RCPNode.hpp:976
Teuchos::DanglingReferenceError
Dangling reference error exception class.
Definition: Teuchos_Exceptions.hpp:101
Teuchos::RCPNodeHandle::RCPNodeHandle
RCPNodeHandle(const RCPNodeHandle &node_ref)
Copy constructor.
Definition: Teuchos_RCPNode.hpp:808
Teuchos::RCPNode::get_extra_data
const any & get_extra_data(const std::string &type_name, const std::string &name) const
Definition: Teuchos_RCPNode.hpp:251
TEUCHOS_TEST_FOR_EXCEPT
#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.
Definition: Teuchos_TestForException.hpp:307
Teuchos::RCPNode::RCPNode
RCPNode(bool has_ownership_in)
Definition: Teuchos_RCPNode.hpp:157
Teuchos::ActiveRCPNodesSetup
Sets up node tracing and prints remaining RCPNodes on destruction.
Definition: Teuchos_RCPNode.hpp:704
Teuchos::RCPNodeHandle::operator<<
std::ostream & operator<<(std::ostream &out, const RCPNodeHandle &node)
Ouput stream operator for RCPNodeHandle.
Definition: Teuchos_RCPNode.hpp:1060
Teuchos::RCPNodeThrowDeleter::get
RCPNode * get() const
Definition: Teuchos_RCPNode.hpp:1105
Teuchos::RCPNodeHandle::RCPNodeHandle
RCPNodeHandle(ENull null_arg=null)
Default constructor.
Definition: Teuchos_RCPNode.hpp:752
Teuchos::RCPNodeHandle::has_ownership
bool has_ownership() const
Definition: Teuchos_RCPNode.hpp:930
Teuchos::RCPNodeTmpl::is_valid_ptr
virtual bool is_valid_ptr() const
Definition: Teuchos_RCPNode.hpp:595
Teuchos::RCPNode::strong_count
int strong_count() const
Definition: Teuchos_RCPNode.hpp:203
Teuchos::RCPNodeTracer
Debug-mode RCPNode tracing class.
Definition: Teuchos_RCPNode.hpp:369
Teuchos::RCPNodeTmpl::~RCPNodeTmpl
~RCPNodeTmpl()
Definition: Teuchos_RCPNode.hpp:586
Teuchos::RCPNodeTracer::getCommonDebugNotesString
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
Definition: Teuchos_RCPNode.cpp:630
Teuchos::RCPNodeTracer::RCPNodeStatistics
RCP statistics struct.
Definition: Teuchos_RCPNode.hpp:376
Teuchos::RCPNodeHandle::create_strong
RCPNodeHandle create_strong() const
Return a strong handle.
Definition: Teuchos_RCPNode.hpp:863
Teuchos::RCPNodeHandle::node_ptr
RCPNode * node_ptr() const
Return a pointer to the underlying RCPNode.
Definition: Teuchos_RCPNode.hpp:870
Teuchos::RCPNodeTracer::isTracingActiveRCPNodes
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
Definition: Teuchos_RCPNode.cpp:299
TEUCHOS_ASSERT
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Definition: Teuchos_Assert.hpp:55
Teuchos::RCPNodeHandle::debug_assert_valid_ptr
void debug_assert_valid_ptr(const RCPType &rcp_obj) const
Definition: Teuchos_RCPNode.hpp:996
Teuchos::RCPNodeHandle::get_extra_data
const any & get_extra_data(const std::string &type_name, const std::string &name) const
Definition: Teuchos_RCPNode.hpp:954
Teuchos::typeName
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.
Definition: Teuchos_TypeNameTraits.hpp:115
Teuchos::RCPNodeHandle::get_extra_data
any & get_extra_data(const std::string &type_name, const std::string &name)
Definition: Teuchos_RCPNode.hpp:946
Teuchos::RCPNodeTmpl::get_dealloc
const Dealloc_T & get_dealloc() const
Definition: Teuchos_RCPNode.hpp:583
TEUCHOS_TEST_FOR_TERMINATION
#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...
Definition: Teuchos_TestForException.hpp:379
Teuchos::RCPNode::get_optional_extra_data
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
Definition: Teuchos_RCPNode.hpp:261
Teuchos::RCPNodeTmpl::get_base_obj_type_name
const std::string get_base_obj_type_name() const
Definition: Teuchos_RCPNode.hpp:667
Teuchos::RCPNodeThrowDeleter::RCPNodeThrowDeleter
RCPNodeThrowDeleter(RCPNode *node)
Definition: Teuchos_RCPNode.hpp:1088
Teuchos::RCPNodeHandle::weak_count
int weak_count() const
The weak count for this RCPNode, or 0 if the node is NULL.
Definition: Teuchos_RCPNode.hpp:899
Teuchos::RCPNode::weak_count
int weak_count() const
Definition: Teuchos_RCPNode.hpp:208
Teuchos::RCPNodeHandle::get_optional_extra_data
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
Definition: Teuchos_RCPNode.hpp:969
Teuchos::RCPNodeTmpl::RCPNodeTmpl
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in)
For defined types.
Definition: Teuchos_RCPNode.hpp:562
Teuchos::RCPNodeHandle::RCPNodeHandle
RCPNodeHandle(RCPNode *node, ERCPStrength strength_in=RCP_STRONG, bool newNode=true)
Constructor that takes a pointer to an RCPNode.
Definition: Teuchos_RCPNode.hpp:759
Teuchos::RCPNodeHandle::create_strong_lock
RCPNodeHandle create_strong_lock() const
Return a strong handle if possible using thread safe atomics.
Definition: Teuchos_RCPNode.hpp:846
Teuchos::RCPNodeThrowDeleter::release
void release()
Releaes the RCPNode pointer before the destructor is called.
Definition: Teuchos_RCPNode.hpp:1110
Teuchos::RCPNodeTmpl::throw_invalid_obj_exception
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
Definition: Teuchos_RCPNode.hpp:624
Teuchos::RCPNodeThrowDeleter::~RCPNodeThrowDeleter
~RCPNodeThrowDeleter()
Called with node_!=0 when an exception is thrown.
Definition: Teuchos_RCPNode.hpp:1096
Teuchos::RCPNodeHandle::same_node
bool same_node(const RCPNodeHandle &node2) const
Whether the RCPNode for which node2 is a handle is the same RCPNode as this object's RCPNode.
Definition: Teuchos_RCPNode.hpp:888
Teuchos::debugAssertStrength
void debugAssertStrength(ERCPStrength strength)
Definition: Teuchos_RCPNode.hpp:94
Teuchos::RCPNodeHandle::~RCPNodeHandle
~RCPNodeHandle()
Destructor.
Definition: Teuchos_RCPNode.hpp:840
Teuchos_TypeNameTraits.hpp
Defines basic traits returning the name of a type in a portable and readable way.
Teuchos_ConfigDefs.hpp
Teuchos header file which uses auto-configuration information to include necessary C++ headers.
Teuchos::ERCPNodeLookup
ERCPNodeLookup
Used to determine if RCPNode lookup is performed or not.
Definition: Teuchos_RCPNode.hpp:91
Teuchos::RCPNode
Node class to keep track of address and the reference count for a reference-counted utility class and...
Definition: Teuchos_RCPNode.hpp:154
Teuchos::RCPNode::has_ownership
bool has_ownership() const
Definition: Teuchos_RCPNode.hpp:239
Teuchos::RCPNodeHandle::is_valid_ptr
bool is_valid_ptr() const
Whether the underlying pointer is valid.
Definition: Teuchos_RCPNode.hpp:880
Teuchos::RCPNodeHandle::swap
void swap(RCPNodeHandle &node_ref)
Swap the contents of node_ref with *this.
Definition: Teuchos_RCPNode.hpp:815
Teuchos::RCPNode::deincr_count
int deincr_count(const ERCPStrength strength)
Definition: Teuchos_RCPNode.hpp:223
Teuchos::RCPNodeHandle::is_node_null
bool is_node_null() const
Whether the underlying RCPNode is NULL.
Definition: Teuchos_RCPNode.hpp:874
Teuchos::RCPNodeThrowDeleter
Deletes a (non-owning) RCPNode but not it's underlying object in case of a throw.
Definition: Teuchos_RCPNode.hpp:1085
Teuchos::RCPNode::incr_count
void incr_count(const ERCPStrength strength)
Definition: Teuchos_RCPNode.hpp:213
Teuchos::RCPNode::~RCPNode
virtual ~RCPNode()
Definition: Teuchos_RCPNode.hpp:167
Teuchos::RCPNodeHandle::total_count
int total_count() const
The sum of the weak and string counts.
Definition: Teuchos_RCPNode.hpp:906
Teuchos::ToStringTraits
Default traits class for converting objects into strings.
Definition: Teuchos_toString.hpp:60
Teuchos::RCPNodeTmpl::delete_obj
virtual void delete_obj()
Delete the underlying object. Will abort if an exception is detected in the destructor.
Definition: Teuchos_RCPNode.hpp:602
Teuchos::RCPNodeTmpl::get_nonconst_dealloc
Dealloc_T & get_nonconst_dealloc()
Definition: Teuchos_RCPNode.hpp:580
Teuchos::RCPNodeHandle
Handle class that manages the RCPNode's reference counting.
Definition: Teuchos_RCPNode.hpp:749
Teuchos_map.hpp
Provides std::map class for deficient platforms.
Teuchos_any.hpp
Modified boost::any class for holding a templated value.
Teuchos::RCPNode::pre_delete_extra_data
void pre_delete_extra_data()
Definition: Teuchos_RCPNode.hpp:286
Teuchos::RCPNodeHandle::set_extra_data
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
Definition: Teuchos_RCPNode.hpp:937
Teuchos::RCPNodeHandle::strength
ERCPStrength strength() const
The strength of this handle.
Definition: Teuchos_RCPNode.hpp:920
Teuchos::RCPNodeTracer::addNewRCPNode
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
Definition: Teuchos_RCPNode.cpp:421
Teuchos::EPrePostDestruction
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
Definition: Teuchos_RCPNode.hpp:79
Teuchos::RCPNodeTmpl::RCPNodeTmpl
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in, ENull)
For undefined types .
Definition: Teuchos_RCPNode.hpp:571
Teuchos
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
Teuchos::ERCPStrength
ERCPStrength
Used to specify if the pointer is weak or strong.
Definition: Teuchos_RCPNode.hpp:85
Teuchos::RCPNode::has_ownership
void has_ownership(bool has_ownership_in)
Definition: Teuchos_RCPNode.hpp:234
Teuchos::RCPNodeTracer::getExistingRCPNode
static RCPNode * getExistingRCPNode(T *p)
Return a raw pointer to an existing owning RCPNode given the address to the underlying object if it e...
Definition: Teuchos_RCPNode.hpp:529
Teuchos::RCPNodeHandle::create_weak
RCPNodeHandle create_weak() const
Return a weak handle.
Definition: Teuchos_RCPNode.hpp:856
Teuchos::RCPNodeHandle::assert_valid_ptr
void assert_valid_ptr(const RCPType &rcp_obj) const
Definition: Teuchos_RCPNode.hpp:985
Teuchos::RCPNode::attemptIncrementStrongCountFromNonZeroValue
bool attemptIncrementStrongCountFromNonZeroValue()
attemptIncrementStrongCountFromNonZeroValue() supports weak to strong conversion but this is forward ...
Definition: Teuchos_RCPNode.hpp:175
TEUCHOS_TEST_FOR_EXCEPT_MSG
#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.
Definition: Teuchos_TestForException.hpp:327
TEUCHOS_TEST_FOR_EXCEPTION
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Definition: Teuchos_TestForException.hpp:170
Teuchos::RCPNodeHandle::strong_count
int strong_count() const
The strong count for this RCPNode, or 0 if the node is NULL.
Definition: Teuchos_RCPNode.hpp:892
Teuchos::any
Modified boost::any class, which is a container for a templated value.
Definition: Teuchos_any.hpp:154
Teuchos::RCPNodeTmpl
Templated implementation class of RCPNode that has the responsibility for deleting the reference-coun...
Definition: Teuchos_RCPNode.hpp:559
Teuchos::RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr
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's typ...
Definition: Teuchos_RCPNode.hpp:499
Teuchos::RCPNodeHandle::get_optional_extra_data
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
Definition: Teuchos_RCPNode.hpp:961