Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_RCPNode.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_RCP_NODE_HPP
43 #define TEUCHOS_RCP_NODE_HPP
44 
45 
52 #include "Teuchos_ConfigDefs.hpp"
53 #include "Teuchos_any.hpp"
54 #include "Teuchos_map.hpp"
55 #include "Teuchos_ENull.hpp"
56 #include "Teuchos_Assert.hpp"
57 #include "Teuchos_Exceptions.hpp"
59 #include "Teuchos_toString.hpp"
60 #include "Teuchos_getBaseObjVoidPtr.hpp"
61 
62 #if defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE) && !defined(DISABLE_ATOMIC_COUNTERS)
63 #include <atomic>
64 #define USING_ATOMICS
65 #endif
66 
67 namespace Teuchos {
68 
69 #ifdef USING_ATOMICS
70 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) std::atomic<T> VAR
71 #else
72 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) T VAR
73 #endif
74 
79 enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
80 
85 enum ERCPStrength { RCP_STRONG=0, RCP_WEAK=1 };
86 
91 enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP };
92 
94 inline void debugAssertStrength(ERCPStrength strength)
95 {
96 #ifdef TEUCHOS_DEBUG
97  switch (strength) {
98  case RCP_STRONG:
99  // fall through
100  case RCP_WEAK:
101  return; // Fine
102  default:
104  true, std::logic_error, "Teuchos::RCPNode: ERCPStrength enum value "
105  << strength << " is invalid (neither RCP_STRONG = " << RCP_STRONG
106  << " nor RCP_WEAK = " << RCP_WEAK << ").");
107  }
108 #else
109  (void) strength; // Silence "unused variable" compiler warning.
110 #endif // TEUCHOS_DEBUG
111 }
112 
118 template<>
119 class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
120 public:
121  static std::string toString( const ERCPStrength &t )
122  {
123  switch (t) {
124  case RCP_STRONG:
125  return "RCP_STRONG";
126  case RCP_WEAK:
127  return "RCP_WEAK";
128  default:
129  // Should never get here but fall through ...
130  break;
131  }
132  // Should never get here!
133 #ifdef TEUCHOS_DEBUG
135 #else
136  return "";
137 #endif
138  }
139 };
140 
141 
153 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
154 public:
156  RCPNode(bool has_ownership_in)
157  : has_ownership_(has_ownership_in), extra_data_map_(NULL)
158 #ifdef TEUCHOS_DEBUG
159  ,insertion_number_(-1)
160 #endif // TEUCHOS_DEBUG
161  {
162  count_[RCP_STRONG] = 0;
163  count_[RCP_WEAK] = 0;
164  }
166  virtual ~RCPNode()
167  {
168  if(extra_data_map_)
169  delete extra_data_map_;
170  }
175  {
176 #ifdef USING_ATOMICS
177  // this code follows the boost method
178  int strong_count_non_atomic = count_[RCP_STRONG];
179  for( ;; ) {
180  if (strong_count_non_atomic == 0) {
181  return false;
182  }
183  if (std::atomic_compare_exchange_weak( &count_[RCP_STRONG],
184  &strong_count_non_atomic, strong_count_non_atomic + 1)) {
185  return true;
186  }
187  }
188 #else
189  // the non-thread safe version - this fails with threads because
190  // strong_count_ can become 0 after the check if it is 0 and we would
191  // return true with no valid object
192  if (count_[RCP_STRONG] == 0) {
193  return false;
194  }
195  else {
196  ++count_[RCP_STRONG];
197  return true;
198  }
199 #endif
200  }
202  int strong_count() const
203  {
204  return count_[RCP_STRONG];
205  }
207  int weak_count() const // not atomically safe
208  {
209  return count_[RCP_WEAK] - (count_[RCP_STRONG] ? 1 : 0 ); // weak is +1 when strong > 0
210  }
212  void incr_count( const ERCPStrength strength )
213  {
214  debugAssertStrength(strength);
215  if (++count_[strength] == 1) {
216  if (strength == RCP_STRONG) {
217  ++count_[RCP_WEAK]; // this is the special condition - the first strong creates a weak
218  }
219  }
220  }
222  int deincr_count( const ERCPStrength strength )
223  {
224  debugAssertStrength(strength);
225 #ifdef BREAK_THREAD_SAFETY_OF_DEINCR_COUNT
226  --count_[strength];
227  return count_[strength]; // not atomically valid
228 #else
229  return --count_[strength];
230 #endif
231  }
233  void has_ownership(bool has_ownership_in)
234  {
235  has_ownership_ = has_ownership_in;
236  }
238  bool has_ownership() const
239  {
240  return has_ownership_;
241  }
243  void set_extra_data(
244  const any &extra_data, const std::string& name,
245  EPrePostDestruction destroy_when, bool force_unique );
247  any& get_extra_data( const std::string& type_name,
248  const std::string& name );
250  const any& get_extra_data( const std::string& type_name,
251  const std::string& name
252  ) const
253  {
254  return const_cast<RCPNode*>(this)->get_extra_data(type_name, name);
255  }
257  any* get_optional_extra_data(const std::string& type_name,
258  const std::string& name );
261  const std::string& type_name, const std::string& name
262  ) const
263  {
264  return const_cast<RCPNode*>(this)->get_optional_extra_data(type_name, name);
265  }
267  virtual bool is_valid_ptr() const = 0;
269  virtual void delete_obj() = 0;
271  virtual void throw_invalid_obj_exception(
272  const std::string& rcp_type_name,
273  const void* rcp_ptr,
274  const RCPNode* rcp_node_ptr,
275  const void* rcp_obj_ptr
276  ) const = 0;
278  virtual const std::string get_base_obj_type_name() const = 0;
279 #ifdef TEUCHOS_DEBUG
280 
281  virtual const void* get_base_obj_map_key_void_ptr() const = 0;
282 #endif
283 protected:
286  {
287  if(extra_data_map_)
288  impl_pre_delete_extra_data();
289  }
290 private:
291  struct extra_data_entry_t {
292  extra_data_entry_t() : destroy_when(POST_DESTROY) {}
293  extra_data_entry_t( const any &_extra_data, EPrePostDestruction _destroy_when )
294  : extra_data(_extra_data), destroy_when(_destroy_when)
295  {}
296  any extra_data;
297  EPrePostDestruction destroy_when;
298  };
299  typedef Teuchos::map<std::string,extra_data_entry_t> extra_data_map_t;
300 
301  TEUCHOS_RCP_DECL_ATOMIC(count_[2], int);
302  TEUCHOS_RCP_DECL_ATOMIC(has_ownership_, bool);
303 
304  extra_data_map_t *extra_data_map_;
305  // Above is made a pointer to reduce overhead for the general case when this
306  // is not used. However, this adds just a little bit to the overhead when
307  // it is used.
308  // Provides the "basic" guarantee!
309  void impl_pre_delete_extra_data();
310  // Not defined and not to be called
311  RCPNode();
312  RCPNode(const RCPNode&);
313  RCPNode& operator=(const RCPNode&);
314 #ifdef TEUCHOS_DEBUG
315  // removed atomic because mutex handles it - atomic would be redundant
316  int insertion_number_;
317 public:
318  void set_insertion_number(int insertion_number_in)
319  {
320  insertion_number_ = insertion_number_in;
321  }
322  int insertion_number() const
323  {
324  return insertion_number_;
325  }
326 #endif // TEUCHOS_DEBUG
327 };
328 
329 
334 TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error( const std::string &type_name );
335 
336 
337 #ifdef TEUCHOS_DEBUG
338  // to fully implement abort for TEUCHOS_STANDARD_CATCH_STATEMENTS in the cpp
340  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const std::exception &);
342  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor(const int &);
344  TEUCHOSCORE_LIB_DLL_EXPORT void abort_for_exception_in_destructor();
345  // called when RCPNode detects any exception in a destructor
346  #define TEUCHOS_CATCH_AND_ABORT \
347  catch(const std::exception &excpt) { abort_for_exception_in_destructor(excpt); } \
348  catch(const int &excpt_code) { abort_for_exception_in_destructor(excpt_code); } \
349  catch(...) { abort_for_exception_in_destructor(); }
350 #endif
351 
368 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
369 public:
370 
373 
377  : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
378  totalNumRCPNodeDeletions(0)
379  {}
380  long int maxNumRCPNodes;
381  long int totalNumRCPNodeAllocations;
382  long int totalNumRCPNodeDeletions;
383  };
384 
386 
389 
395  static bool isTracingActiveRCPNodes();
396 
397 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
398 
415  static void setTracingActiveRCPNodes(bool tracingActiveNodes);
416 #endif
417 
421  static int numActiveRCPNodes();
422 
424  static RCPNodeStatistics getRCPNodeStatistics() ;
425 
427  static void printRCPNodeStatistics(
428  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out);
429 
433  static void setPrintRCPNodeStatisticsOnExit(
434  bool printRCPNodeStatisticsOnExit);
435 
439  static bool getPrintRCPNodeStatisticsOnExit();
440 
444  static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit);
445 
449  static bool getPrintActiveRcpNodesOnExit();
450 
466  static void printActiveRCPNodes(std::ostream &out);
467 
469 
474 
479  static void addNewRCPNode(RCPNode* rcp_node,
480  const std::string &info );
481 
487  static void removeRCPNode( RCPNode* rcp_node );
488 
497  template<class T>
498  static const void* getRCPNodeBaseObjMapKeyVoidPtr(T *p)
499  {
500 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
501  return getBaseObjVoidPtr(p);
502 #else
503  // This will not return the base address for polymorphic types if
504  // multiple inheritance and/or virtual bases are used but returning the
505  // static_cast should be okay in how it is used. It is just that the
506  // RCPNode tracing support will not always be able to figure out if two
507  // pointers of different type are pointing to the same object or not.
508  return static_cast<const void*>(p);
509 #endif
510  }
511 
518  static RCPNode* getExistingRCPNodeGivenLookupKey(
519  const void* lookupKey);
520 
527  template<class T>
529  {
530  return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
531  }
532 
534  static std::string getActiveRCPNodeHeaderString();
535 
537  static std::string getCommonDebugNotesString();
538 
540 
541 };
542 
543 
544 #ifdef TEUCHOS_DEBUG
545 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \
546  " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n"
547 #else
548 # define TEUCHOS_RCP_INSERION_NUMBER_STR()
549 #endif
550 
551 
557 template<class T, class Dealloc_T>
558 class RCPNodeTmpl : public RCPNode {
559 public:
561  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in)
562  : RCPNode(has_ownership_in), ptr_(p),
563 #ifdef TEUCHOS_DEBUG
564  base_obj_map_key_void_ptr_(RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
565  deleted_ptr_(0),
566 #endif
567  dealloc_(dealloc)
568  {}
570  RCPNodeTmpl(T* p, Dealloc_T dealloc, bool has_ownership_in, ENull)
571  : RCPNode(has_ownership_in), ptr_(p),
572 #ifdef TEUCHOS_DEBUG
573  base_obj_map_key_void_ptr_(0),
574  deleted_ptr_(0),
575 #endif
576  dealloc_(dealloc)
577  {}
579  Dealloc_T& get_nonconst_dealloc()
580  { return dealloc_; }
582  const Dealloc_T& get_dealloc() const
583  { return dealloc_; }
586  {
587 #ifdef TEUCHOS_DEBUG
589  "Error, the underlying object must be explicitly deleted before deleting"
590  " the node object!" );
591 #endif
592  }
594  virtual bool is_valid_ptr() const
595  {
596  return ptr_ != 0;
597  }
601  virtual void delete_obj()
602  {
603  if (ptr_!= 0) {
604  this->pre_delete_extra_data(); // Should not throw!
605  T* tmp_ptr = ptr_;
606 #ifdef TEUCHOS_DEBUG
607  deleted_ptr_ = tmp_ptr;
608 #endif
609  ptr_ = 0;
610  if (has_ownership()) {
611 #ifdef TEUCHOS_DEBUG
612  try {
613 #endif
614  dealloc_.free(tmp_ptr);
615 #ifdef TEUCHOS_DEBUG
616  }
617  TEUCHOS_CATCH_AND_ABORT
618 #endif
619  }
620  }
621  }
624  const std::string& rcp_type_name,
625  const void* rcp_ptr,
626  const RCPNode* rcp_node_ptr,
627  const void* rcp_obj_ptr
628  ) const
629  {
630  TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
631  const T* deleted_ptr =
632 #ifdef TEUCHOS_DEBUG
633  deleted_ptr_
634 #else
635  0
636 #endif
637  ;
638  TEUCHOS_ASSERT(rcp_node_ptr);
640  "Error, an attempt has been made to dereference the underlying object\n"
641  "from a weak smart pointer object where the underling object has already\n"
642  "been deleted since the strong count has already gone to zero.\n"
643  "\n"
644  "Context information:\n"
645  "\n"
646  " RCP type: " << rcp_type_name << "\n"
647  " RCP address: " << rcp_ptr << "\n"
648  " RCPNode type: " << typeName(*this) << "\n"
649  " RCPNode address: " << rcp_node_ptr << "\n"
650  TEUCHOS_RCP_INSERION_NUMBER_STR()
651  " RCP ptr address: " << rcp_obj_ptr << "\n"
652  " Concrete ptr address: " << deleted_ptr << "\n"
653  "\n"
655  );
656  // 2008/09/22: rabartl: Above, we do not provide the concreate object
657  // type or the concrete object address. In the case of the concrete
658  // object address, in a non-debug build, we don't want to pay a price
659  // for extra storage that we strictly don't need. In the case of the
660  // concrete object type name, we don't want to force non-debug built
661  // code to have the require that types be fully defined in order to use
662  // the memory management software. This is related to bug 4016.
663 
664  }
666  const std::string get_base_obj_type_name() const
667  {
668 #ifdef TEUCHOS_DEBUG
669  return TypeNameTraits<T>::name();
670 #else
671  return "UnknownType";
672 #endif
673  }
674 #ifdef TEUCHOS_DEBUG
675 
676  const void* get_base_obj_map_key_void_ptr() const
677  {
678  return base_obj_map_key_void_ptr_;
679  }
680 #endif
681 private:
682  T *ptr_;
683 #ifdef TEUCHOS_DEBUG
684  const void *base_obj_map_key_void_ptr_;
685  T *deleted_ptr_;
686 #endif
687  Dealloc_T dealloc_;
688  // not defined and not to be called
689  RCPNodeTmpl();
690  RCPNodeTmpl(const RCPNodeTmpl&);
691  RCPNodeTmpl& operator=(const RCPNodeTmpl&);
692 
693 }; // end class RCPNodeTmpl<T>
694 
695 
703 class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
704 public:
710  void foo();
711 private:
712  static int count_;
713 };
714 
715 
716 } // namespace Teuchos
717 
718 
719 namespace {
720 // This static variable is declared before all other static variables that
721 // depend on RCP or other classes. Therefore, this static variable will be
722 // deleted *after* all of these other static variables that depend on RCP or
723 // created classes go away! This ensures that the node tracing machinery is
724 // setup and torn down correctly (this is the same trick used by the standard
725 // stream objects in many compiler implementations).
726 Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
727 } // namespace (anonymous)
728 
729 
730 namespace Teuchos {
731 
748 class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
749 public:
751  RCPNodeHandle (ENull null_arg = null)
752  : node_ (0), strength_ (RCP_STRONG)
753  {
754  (void) null_arg; // Silence "unused variable" compiler warning.
755  }
756 
759  ERCPStrength strength_in = RCP_STRONG,
760  bool newNode = true)
761  : node_ (node), strength_ (strength_in)
762  {
763 #ifdef TEUCHOS_DEBUG
764  TEUCHOS_ASSERT(node);
765 #endif // TEUCHOS_DEBUG
766 
767  bind();
768 
769 #ifdef TEUCHOS_DEBUG
770  // Add the node if this is the first RCPNodeHandle to get it. We have
771  // to add it because unbind() will call the remove_RCPNode(...) function
772  // and it needs to match when node tracing is on from the beginning.
773  if (RCPNodeTracer::isTracingActiveRCPNodes() && newNode) {
774  std::ostringstream os;
775  os << "{T=Unknown, ConcreteT=Unknown, p=Unknown,"
776  << " has_ownership="<<node_->has_ownership()<<"}";
777  RCPNodeTracer::addNewRCPNode(node_, os.str());
778  }
779 #else
780  (void) newNode; // Silence "unused variable" compiler warning.
781 #endif // TEUCHOS_DEBUG
782  }
783 
784 #ifdef TEUCHOS_DEBUG
785 
786  template<typename T>
787  RCPNodeHandle (RCPNode* node, T *p, const std::string &T_name,
788  const std::string &ConcreteT_name,
789  const bool has_ownership_in,
790  ERCPStrength strength_in = RCP_STRONG)
791  : node_ (node), strength_ (strength_in)
792  {
793  TEUCHOS_ASSERT(strength_in == RCP_STRONG); // Can't handle weak yet!
794  TEUCHOS_ASSERT(node_);
795  bind();
797  std::ostringstream os;
798  os << "{T="<<T_name<<", ConcreteT="<< ConcreteT_name
799  <<", p="<<static_cast<const void*>(p)
800  <<", has_ownership="<<has_ownership_in<<"}";
801  RCPNodeTracer::addNewRCPNode(node_, os.str());
802  }
803  }
804 #endif // TEUCHOS_DEBUG
805 
807  RCPNodeHandle (const RCPNodeHandle& node_ref)
808  : node_ (node_ref.node_), strength_ (node_ref.strength_)
809  {
810  bind();
811  }
812 
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 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.