Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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.
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
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();
796 if (RCPNodeTracer::isTracingActiveRCPNodes()) {
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...
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)