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 #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 
815  : node_ (node_ref.node_), strength_ (node_ref.strength_)
816  {
817  node_ref.node_ = 0;
818  node_ref.strength_ = RCP_STRONG;
819  }
820 
822  void swap (RCPNodeHandle& node_ref) {
823  std::swap (node_ref.node_, node_);
824  std::swap (node_ref.strength_, strength_);
825  }
826 
827 
828 
834  RCPNodeHandle& operator= (ENull) {
835  unbind(); // May throw in some cases
836  node_ = 0;
837  strength_ = RCP_STRONG;
838  return *this;
839  }
840 
846  RCPNodeHandle& operator= (const RCPNodeHandle& node_ref) {
847  // NOTE: Don't need to check assignment to self since user-facing classes
848  // do that!
849  unbind(); // May throw in some cases
850  node_ = node_ref.node_;
851  strength_ = node_ref.strength_;
852  bind();
853  return *this;
854  }
855 
861  RCPNodeHandle& operator= (RCPNodeHandle&& node_ref) {
862  // NOTE: Don't need to check assignment to self since user-facing classes
863  // do that!
864  unbind(); // May throw in some cases
865  node_ = node_ref.node_;
866  strength_ = node_ref.strength_;
867  node_ref.node_ = 0;
868  node_ref.strength_ = RCP_STRONG;
869  return *this;
870  }
871 
874  unbind();
875  }
876 
878  // otherwise return a null handle
880  // make weak handle
881  RCPNodeHandle possibleStrongNode(node_, RCP_WEAK, false);
882  if (possibleStrongNode.attemptConvertWeakToStrong()) {
883  return possibleStrongNode; // success - we have a good strong handle
884  }
885  return RCPNodeHandle(); // failure - return an empty handle
886  }
887 
890  if (node_) {
891  return RCPNodeHandle(node_, RCP_WEAK, false);
892  }
893  return RCPNodeHandle();
894  }
897  if (node_) {
898  return RCPNodeHandle(node_, RCP_STRONG, false);
899  }
900  return RCPNodeHandle();
901  }
903  RCPNode* node_ptr() const {
904  return node_;
905  }
907  bool is_node_null() const {
908  return node_==0;
909  }
913  bool is_valid_ptr() const {
914  if (node_) {
915  return node_->is_valid_ptr();
916  }
917  return true; // Null is a valid ptr!
918  }
921  bool same_node(const RCPNodeHandle &node2) const {
922  return node_ == node2.node_;
923  }
925  int strong_count() const {
926  if (node_) {
927  return node_->strong_count();
928  }
929  return 0;
930  }
932  int weak_count() const {
933  if (node_) {
934  return node_->weak_count(); // Not atomically safe
935  }
936  return 0;
937  }
939  int total_count() const {
940  if (node_) {
941  return node_->strong_count() + node_->weak_count(); // not atomically safe
942  }
943  return 0;
944  }
947  return strength_;
948  }
950  void has_ownership(bool has_ownership_in)
951  {
952  if (node_)
953  node_->has_ownership(has_ownership_in);
954  }
956  bool has_ownership() const
957  {
958  if (node_)
959  return node_->has_ownership();
960  return false;
961  }
964  const any &extra_data, const std::string& name,
965  EPrePostDestruction destroy_when, bool force_unique
966  )
967  {
968  debug_assert_not_null();
969  node_->set_extra_data(extra_data, name, destroy_when, force_unique);
970  }
972  any& get_extra_data( const std::string& type_name,
973  const std::string& name
974  )
975  {
976  debug_assert_not_null();
977  return node_->get_extra_data(type_name, name);
978  }
980  const any& get_extra_data( const std::string& type_name,
981  const std::string& name
982  ) const
983  {
984  return const_cast<RCPNodeHandle*>(this)->get_extra_data(type_name, name);
985  }
988  const std::string& type_name, const std::string& name
989  )
990  {
991  debug_assert_not_null();
992  return node_->get_optional_extra_data(type_name, name);
993  }
996  const std::string& type_name, const std::string& name
997  ) const
998  {
999  return const_cast<RCPNodeHandle*>(this)->get_optional_extra_data(type_name, name);
1000  }
1003  {
1004 #ifdef TEUCHOS_DEBUG
1005  if (!node_)
1006  throw_null_ptr_error(typeName(*this));
1007 #endif
1008  }
1010  template<class RCPType>
1011  void assert_valid_ptr(const RCPType& rcp_obj) const
1012  {
1013  if (!node_)
1014  return; // Null is a valid pointer!
1015  if (!is_valid_ptr()) {
1016  node_->throw_invalid_obj_exception( typeName(rcp_obj),
1017  this, node_, rcp_obj.access_private_ptr() );
1018  }
1019  }
1021  template<class RCPType>
1022  void debug_assert_valid_ptr(const RCPType& rcp_obj) const
1023  {
1024 #ifdef TEUCHOS_DEBUG
1025  assert_valid_ptr(rcp_obj);
1026 #endif
1027  }
1028 #ifdef TEUCHOS_DEBUG
1029  const void* get_base_obj_map_key_void_ptr() const
1030  {
1031  if (node_)
1032  return node_->get_base_obj_map_key_void_ptr();
1033  return 0;
1034  }
1035 #endif
1036 private:
1037  RCPNode *node_;
1038  ERCPStrength strength_;
1039  // atomically safe conversion of a weak handle to a strong handle if
1040  // possible - if not possible nothing changes
1041  bool attemptConvertWeakToStrong() {
1042  if (node_->attemptIncrementStrongCountFromNonZeroValue()) {
1043  // because we converted strong + 1 we account for this by doing weak - 1
1044  node_->deincr_count(RCP_WEAK);
1045  // we have successfully incremented the strong count by one
1046  strength_ = RCP_STRONG;
1047  return true;
1048  }
1049  return false;
1050  }
1051  inline void bind()
1052  {
1053  if (node_)
1054  node_->incr_count(strength_);
1055  }
1056  inline void unbind()
1057  {
1058  if (node_) {
1059  if(strength_ == RCP_STRONG) {
1060  // only strong checks for --strong == 0
1061  if (node_->deincr_count(RCP_STRONG) == 0) {
1062  unbindOneStrong();
1063  // but if strong hits 0 it also decrements weak_count_plus which
1064  // is weak + (strong != 0)
1065  if( node_->deincr_count(RCP_WEAK) == 0) {
1066  unbindOneTotal();
1067  }
1068  }
1069  }
1070  else if(node_->deincr_count(RCP_WEAK) == 0) { // weak checks here
1071  unbindOneTotal();
1072  }
1073  }
1074  }
1075  void unbindOneStrong();
1076  void unbindOneTotal();
1077 };
1078 
1079 
1084 inline
1085 std::ostream& operator<<(std::ostream& out, const RCPNodeHandle& node)
1086 {
1087  // mfh 15 Sep 2015: Make sure that NULL pointers print consistently.
1088  // Clang 3.5 likes to print an empty string in that case, while GCC
1089  // prints 0. Thus, we test if the pointer is NULL and print 0 in
1090  // that case. This is important for MueLu tests, which compare
1091  // string print-outs.
1092  if (node.node_ptr () == NULL) {
1093  out << "0";
1094  } else {
1095  out << node.node_ptr ();
1096  }
1097  return out;
1098 }
1099 
1100 
1110 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
1111 public:
1114  : node_(node)
1115  {}
1122  {
1123  if (node_) {
1124  node_->has_ownership(false); // Avoid actually deleting ptr_
1125  node_->delete_obj(); // Sets the pointer ptr_=0 to allow RCPNode delete
1126  delete node_;
1127  }
1128  }
1130  RCPNode* get() const
1131  {
1132  return node_;
1133  }
1135  void release()
1136  {
1137  node_ = 0;
1138  }
1139 private:
1140  RCPNode *node_;
1141  RCPNodeThrowDeleter(); // Not defined
1142  RCPNodeThrowDeleter(const RCPNodeThrowDeleter&); // Not defined
1143  RCPNodeThrowDeleter& operator=(const RCPNodeThrowDeleter&); // Not defined
1144 };
1145 
1146 
1147 //
1148 // Unit testing support
1149 //
1150 
1151 
1152 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1153 
1154 class SetTracingActiveNodesStack {
1155 public:
1156  SetTracingActiveNodesStack()
1157  {RCPNodeTracer::setTracingActiveRCPNodes(true);}
1158  ~SetTracingActiveNodesStack()
1159  {RCPNodeTracer::setTracingActiveRCPNodes(false);}
1160 };
1161 
1162 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
1163 
1164 #else
1165 
1166 # define SET_RCPNODE_TRACING() (void)0
1167 
1168 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1169 
1170 
1171 } // end namespace Teuchos
1172 
1173 
1174 #endif // TEUCHOS_RCP_NODE_HPP
Dangling reference error exception class.
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
Modified boost::any class for holding a templated value.
void assert_valid_ptr(const RCPType &rcp_obj) 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)
const any & get_extra_data(const std::string &type_name, const std::string &name) const
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.
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.
std::ostream & operator<<(std::ostream &out, const RCPNodeHandle &node)
Ouput stream operator for RCPNodeHandle.
void debug_assert_not_null() const
Modified boost::any class, which is a container for a templated value.
RCPNodeHandle(const RCPNodeHandle &node_ref)
Copy constructor.
RCPNodeHandle create_strong() const
Return a strong handle.
int weak_count() const
RCPNodeHandle(RCPNode *node, ERCPStrength strength_in=RCP_STRONG, bool newNode=true)
Constructor that takes a pointer to an RCPNode.
RCPNodeHandle create_strong_lock() const
Return a strong handle if possible using thread safe atomics.
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.
void debug_assert_valid_ptr(const RCPType &rcp_obj) const
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 .
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...
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...
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.
void debugAssertStrength(ERCPStrength strength)
bool is_node_null() const
Whether the underlying RCPNode is NULL.
ERCPStrength
Used to specify if the pointer is weak or strong.
RCPNode(bool has_ownership_in)
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
int weak_count() const
The weak count for this RCPNode, or 0 if the node is NULL.
static RCPNode * getExistingRCPNode(T *p)
Return a raw pointer to an existing owning RCPNode given the address to the underlying object if it e...
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
Provides std::map class for deficient platforms.
int strong_count() const
virtual bool is_valid_ptr() const
RCPNodeHandle(RCPNodeHandle &&node_ref)
Move constructor.
ERCPStrength strength() const
The strength of this handle.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
bool is_valid_ptr() const
Whether the underlying pointer is valid.
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.
const std::string get_base_obj_type_name() const
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.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
RCPNodeHandle create_weak() const
Return a weak handle.
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in)
For defined types.
bool has_ownership() const
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.
Deletes a (non-owning) RCPNode but not it&#39;s underlying object in case of a throw. ...
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Default traits class for converting objects into strings.
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.
int total_count() const
The sum of the weak and string counts.
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.
const Dealloc_T & get_dealloc() const