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
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
67namespace 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
79enum EPrePostDestruction { PRE_DESTROY, POST_DESTROY };
80
85enum ERCPStrength { RCP_STRONG=0, RCP_WEAK=1 };
86
91enum ERCPNodeLookup { RCP_ENABLE_NODE_LOOKUP, RCP_DISABLE_NODE_LOOKUP };
92
94inline 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
118template<>
119class TEUCHOSCORE_LIB_DLL_EXPORT ToStringTraits<ERCPStrength> {
120public:
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
153class TEUCHOSCORE_LIB_DLL_EXPORT RCPNode {
154public:
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;
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
281 virtual const void* get_base_obj_map_key_void_ptr() const = 0;
282#endif
283protected:
286 {
287 if(extra_data_map_)
288 impl_pre_delete_extra_data();
289 }
290private:
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_;
317public:
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
334TEUCHOSCORE_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
368class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeTracer {
369public:
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)
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
557template<class T, class Dealloc_T>
558class RCPNodeTmpl : public RCPNode {
559public:
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 {}
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
670#else
671 return "UnknownType";
672#endif
673 }
674#ifdef TEUCHOS_DEBUG
676 const void* get_base_obj_map_key_void_ptr() const
677 {
678 return base_obj_map_key_void_ptr_;
679 }
680#endif
681private:
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
703class TEUCHOSCORE_LIB_DLL_EXPORT ActiveRCPNodesSetup {
704public:
710 void foo();
711private:
712 static int count_;
713};
714
715
716} // namespace Teuchos
717
718
719namespace {
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).
726Teuchos::ActiveRCPNodesSetup local_activeRCPNodesSetup;
727} // namespace (anonymous)
728
729
730namespace Teuchos {
731
748class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeHandle {
749public:
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.
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
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
1036private:
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
1084inline
1085std::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
1110class TEUCHOSCORE_LIB_DLL_EXPORT RCPNodeThrowDeleter {
1111public:
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 }
1139private:
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
1154class SetTracingActiveNodesStack {
1155public:
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
Teuchos header file which uses auto-configuration information to include necessary C++ headers.
Defines basic traits returning the name of a type in a portable and readable way.
Modified boost::any class for holding a templated value.
Provides std::map class for deficient platforms.
Sets up node tracing and prints remaining RCPNodes on destruction.
Dangling reference error exception class.
Handle class that manages the RCPNode's reference counting.
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
RCPNodeHandle create_strong() const
Return a strong handle.
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
RCPNodeHandle(RCPNode *node, ERCPStrength strength_in=RCP_STRONG, bool newNode=true)
Constructor that takes a pointer to an RCPNode.
RCPNodeHandle create_weak() const
Return a weak handle.
int total_count() const
The sum of the weak and string counts.
RCPNode * node_ptr() const
Return a pointer to the underlying RCPNode.
any & get_extra_data(const std::string &type_name, const std::string &name)
void debug_assert_not_null() const
RCPNodeHandle(ENull null_arg=null)
Default constructor.
RCPNodeHandle create_strong_lock() const
Return a strong handle if possible using thread safe atomics.
RCPNodeHandle(const RCPNodeHandle &node_ref)
Copy constructor.
bool is_node_null() const
Whether the underlying RCPNode is NULL.
std::ostream & operator<<(std::ostream &out, const RCPNodeHandle &node)
Ouput stream operator for RCPNodeHandle.
void debug_assert_valid_ptr(const RCPType &rcp_obj) const
void assert_valid_ptr(const RCPType &rcp_obj) const
const any & get_extra_data(const std::string &type_name, const std::string &name) const
ERCPStrength strength() const
The strength of this handle.
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
void swap(RCPNodeHandle &node_ref)
Swap the contents of node_ref with *this.
int weak_count() const
The weak count for this RCPNode, or 0 if the node is NULL.
RCPNodeHandle(RCPNodeHandle &&node_ref)
Move constructor.
void has_ownership(bool has_ownership_in)
bool is_valid_ptr() const
Whether the underlying pointer is valid.
int strong_count() const
The strong count for this RCPNode, or 0 if the node is NULL.
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.
Deletes a (non-owning) RCPNode but not it's underlying object in case of a throw.
void release()
Releaes the RCPNode pointer before the destructor is called.
~RCPNodeThrowDeleter()
Called with node_!=0 when an exception is thrown.
Templated implementation class of RCPNode that has the responsibility for deleting the reference-coun...
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in, ENull)
For undefined types .
virtual void delete_obj()
Delete the underlying object. Will abort if an exception is detected in the destructor.
const Dealloc_T & get_dealloc() const
const std::string get_base_obj_type_name() const
virtual bool is_valid_ptr() const
RCPNodeTmpl(T *p, Dealloc_T dealloc, bool has_ownership_in)
For defined types.
Dealloc_T & get_nonconst_dealloc()
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
Debug-mode RCPNode tracing class.
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...
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
static RCPNode * getExistingRCPNode(T *p)
Return a raw pointer to an existing owning RCPNode given the address to the underlying object if it e...
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
Node class to keep track of address and the reference count for a reference-counted utility class and...
bool has_ownership() const
const any & get_extra_data(const std::string &type_name, const std::string &name) const
int strong_count() const
virtual const std::string get_base_obj_type_name() const =0
void incr_count(const ERCPStrength strength)
RCPNode(bool has_ownership_in)
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 =0
int deincr_count(const ERCPStrength strength)
virtual void delete_obj()=0
bool attemptIncrementStrongCountFromNonZeroValue()
attemptIncrementStrongCountFromNonZeroValue() supports weak to strong conversion but this is forward ...
void has_ownership(bool has_ownership_in)
int weak_count() const
const any * get_optional_extra_data(const std::string &type_name, const std::string &name) const
TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error(const std::string &type_name)
Throw that a pointer passed into an RCP object is null.
virtual bool is_valid_ptr() const =0
Default traits class for converting objects into strings.
Modified boost::any class, which is a container for a templated value.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
#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...
#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.
#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.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.
ERCPStrength
Used to specify if the pointer is weak or strong.
ERCPNodeLookup
Used to determine if RCPNode lookup is performed or not.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
void debugAssertStrength(ERCPStrength strength)