10 #ifndef TEUCHOS_RCP_NODE_HPP
11 #define TEUCHOS_RCP_NODE_HPP
23 #include "Teuchos_ENull.hpp"
24 #include "Teuchos_Assert.hpp"
25 #include "Teuchos_Exceptions.hpp"
27 #include "Teuchos_toString.hpp"
28 #include "Teuchos_getBaseObjVoidPtr.hpp"
30 #if defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE) && !defined(DISABLE_ATOMIC_COUNTERS)
38 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) std::atomic<T> VAR
40 # define TEUCHOS_RCP_DECL_ATOMIC(VAR, T) T VAR
72 true, std::logic_error,
"Teuchos::RCPNode: ERCPStrength enum value "
73 << strength <<
" is invalid (neither RCP_STRONG = " << RCP_STRONG
74 <<
" nor RCP_WEAK = " << RCP_WEAK <<
").");
78 #endif // TEUCHOS_DEBUG
125 : has_ownership_(has_ownership_in), extra_data_map_(NULL)
127 ,insertion_number_(-1)
130 count_[RCP_STRONG] = 0;
131 count_[RCP_WEAK] = 0;
137 delete extra_data_map_;
146 int strong_count_non_atomic = count_[RCP_STRONG];
148 if (strong_count_non_atomic == 0) {
151 if (std::atomic_compare_exchange_weak( &count_[RCP_STRONG],
152 &strong_count_non_atomic, strong_count_non_atomic + 1)) {
160 if (count_[RCP_STRONG] == 0) {
164 ++count_[RCP_STRONG];
172 return count_[RCP_STRONG];
177 return count_[RCP_WEAK] - (count_[RCP_STRONG] ? 1 : 0 );
183 if (++count_[strength] == 1) {
184 if (strength == RCP_STRONG) {
193 #ifdef BREAK_THREAD_SAFETY_OF_DEINCR_COUNT
195 return count_[strength];
197 return --count_[strength];
203 has_ownership_ = has_ownership_in;
208 return has_ownership_;
212 const any &extra_data,
const std::string& name,
215 any& get_extra_data(
const std::string& type_name,
216 const std::string& name );
219 const std::string& name
222 return const_cast<RCPNode*
>(
this)->get_extra_data(type_name, name);
225 any* get_optional_extra_data(
const std::string& type_name,
226 const std::string& name );
229 const std::string& type_name,
const std::string& name
232 return const_cast<RCPNode*
>(
this)->get_optional_extra_data(type_name, name);
235 virtual bool is_valid_ptr()
const = 0;
237 virtual void delete_obj() = 0;
239 virtual void throw_invalid_obj_exception(
240 const std::string& rcp_type_name,
243 const void* rcp_obj_ptr
246 virtual const std::string get_base_obj_type_name()
const = 0;
249 virtual const void* get_base_obj_map_key_void_ptr()
const = 0;
256 impl_pre_delete_extra_data();
259 struct extra_data_entry_t {
260 extra_data_entry_t() : destroy_when(POST_DESTROY) {}
262 : extra_data(_extra_data), destroy_when(_destroy_when)
269 TEUCHOS_RCP_DECL_ATOMIC(count_[2],
int);
270 TEUCHOS_RCP_DECL_ATOMIC(has_ownership_,
bool);
272 extra_data_map_t *extra_data_map_;
277 void impl_pre_delete_extra_data();
280 RCPNode(
const RCPNode&);
281 RCPNode& operator=(
const RCPNode&);
284 int insertion_number_;
286 void set_insertion_number(
int insertion_number_in)
288 insertion_number_ = insertion_number_in;
290 int insertion_number()
const
292 return insertion_number_;
294 #endif // TEUCHOS_DEBUG
302 TEUCHOSCORE_LIB_DLL_EXPORT
void throw_null_ptr_error(
const std::string &type_name );
308 TEUCHOSCORE_LIB_DLL_EXPORT
void abort_for_exception_in_destructor(
const std::exception &);
310 TEUCHOSCORE_LIB_DLL_EXPORT
void abort_for_exception_in_destructor(
const int &);
312 TEUCHOSCORE_LIB_DLL_EXPORT
void abort_for_exception_in_destructor();
314 #define TEUCHOS_CATCH_AND_ABORT \
315 catch(const std::exception &excpt) { abort_for_exception_in_destructor(excpt); } \
316 catch(const int &excpt_code) { abort_for_exception_in_destructor(excpt_code); } \
317 catch(...) { abort_for_exception_in_destructor(); }
345 : maxNumRCPNodes(0), totalNumRCPNodeAllocations(0),
346 totalNumRCPNodeDeletions(0)
348 long int maxNumRCPNodes;
349 long int totalNumRCPNodeAllocations;
350 long int totalNumRCPNodeDeletions;
363 static bool isTracingActiveRCPNodes();
365 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
383 static void setTracingActiveRCPNodes(
bool tracingActiveNodes);
389 static int numActiveRCPNodes();
395 static void printRCPNodeStatistics(
401 static void setPrintRCPNodeStatisticsOnExit(
402 bool printRCPNodeStatisticsOnExit);
407 static bool getPrintRCPNodeStatisticsOnExit();
412 static void setPrintActiveRcpNodesOnExit(
bool printActiveRcpNodesOnExit);
417 static bool getPrintActiveRcpNodesOnExit();
434 static void printActiveRCPNodes(std::ostream &out);
447 static void addNewRCPNode(
RCPNode* rcp_node,
448 const std::string &info );
455 static void removeRCPNode(
RCPNode* rcp_node );
468 #ifdef HAS_TEUCHOS_GET_BASE_OBJ_VOID_PTR
469 return getBaseObjVoidPtr(p);
476 return static_cast<const void*
>(p);
486 static RCPNode* getExistingRCPNodeGivenLookupKey(
487 const void* lookupKey);
498 return getExistingRCPNodeGivenLookupKey(getRCPNodeBaseObjMapKeyVoidPtr(p));
502 static std::string getActiveRCPNodeHeaderString();
505 static std::string getCommonDebugNotesString();
513 # define TEUCHOS_RCP_INSERION_NUMBER_STR() \
514 " insertionNumber: " << rcp_node_ptr->insertion_number() << "\n"
516 # define TEUCHOS_RCP_INSERION_NUMBER_STR()
525 template<
class T,
class Dealloc_T>
530 :
RCPNode(has_ownership_in), ptr_(p),
532 base_obj_map_key_void_ptr_(
RCPNodeTracer::getRCPNodeBaseObjMapKeyVoidPtr(p)),
539 :
RCPNode(has_ownership_in), ptr_(p),
541 base_obj_map_key_void_ptr_(0),
557 "Error, the underlying object must be explicitly deleted before deleting"
558 " the node object!" );
575 deleted_ptr_ = tmp_ptr;
582 dealloc_.free(tmp_ptr);
585 TEUCHOS_CATCH_AND_ABORT
592 const std::string& rcp_type_name,
595 const void* rcp_obj_ptr
599 const T* deleted_ptr =
608 "Error, an attempt has been made to dereference the underlying object\n"
609 "from a weak smart pointer object where the underling object has already\n"
610 "been deleted since the strong count has already gone to zero.\n"
612 "Context information:\n"
614 " RCP type: " << rcp_type_name <<
"\n"
615 " RCP address: " << rcp_ptr <<
"\n"
616 " RCPNode type: " <<
typeName(*
this) <<
"\n"
617 " RCPNode address: " << rcp_node_ptr <<
"\n"
618 TEUCHOS_RCP_INSERION_NUMBER_STR()
619 " RCP ptr address: " << rcp_obj_ptr <<
"\n"
620 " Concrete ptr address: " << deleted_ptr <<
"\n"
639 return "UnknownType";
644 const void* get_base_obj_map_key_void_ptr()
const
646 return base_obj_map_key_void_ptr_;
652 const void *base_obj_map_key_void_ptr_;
658 RCPNodeTmpl(
const RCPNodeTmpl&);
659 RCPNodeTmpl& operator=(
const RCPNodeTmpl&);
720 : node_ (0), strength_ (RCP_STRONG)
729 : node_ (node), strength_ (strength_in)
733 #endif // TEUCHOS_DEBUG
742 std::ostringstream os;
743 os <<
"{T=Unknown, ConcreteT=Unknown, p=Unknown,"
744 <<
" has_ownership="<<node_->has_ownership()<<
"}";
749 #endif // TEUCHOS_DEBUG
756 const std::string &ConcreteT_name,
757 const bool has_ownership_in,
759 : node_ (node), strength_ (strength_in)
765 std::ostringstream os;
766 os <<
"{T="<<T_name<<
", ConcreteT="<< ConcreteT_name
767 <<
", p="<<
static_cast<const void*
>(p)
768 <<
", has_ownership="<<has_ownership_in<<
"}";
772 #endif // TEUCHOS_DEBUG
776 : node_ (node_ref.node_), strength_ (node_ref.strength_)
783 : node_ (node_ref.node_), strength_ (node_ref.strength_)
786 node_ref.strength_ = RCP_STRONG;
791 std::swap (node_ref.node_, node_);
792 std::swap (node_ref.strength_, strength_);
805 strength_ = RCP_STRONG;
818 node_ = node_ref.node_;
819 strength_ = node_ref.strength_;
833 node_ = node_ref.node_;
834 strength_ = node_ref.strength_;
836 node_ref.strength_ = RCP_STRONG;
850 if (possibleStrongNode.attemptConvertWeakToStrong()) {
851 return possibleStrongNode;
883 return node_->is_valid_ptr();
890 return node_ == node2.node_;
895 return node_->strong_count();
902 return node_->weak_count();
909 return node_->strong_count() + node_->weak_count();
921 node_->has_ownership(has_ownership_in);
927 return node_->has_ownership();
932 const any &extra_data,
const std::string& name,
936 debug_assert_not_null();
937 node_->set_extra_data(extra_data, name, destroy_when, force_unique);
941 const std::string& name
944 debug_assert_not_null();
945 return node_->get_extra_data(type_name, name);
949 const std::string& name
952 return const_cast<RCPNodeHandle*
>(
this)->get_extra_data(type_name, name);
956 const std::string& type_name,
const std::string& name
959 debug_assert_not_null();
960 return node_->get_optional_extra_data(type_name, name);
964 const std::string& type_name,
const std::string& name
967 return const_cast<RCPNodeHandle*
>(
this)->get_optional_extra_data(type_name, name);
974 throw_null_ptr_error(
typeName(*
this));
978 template<
class RCPType>
983 if (!is_valid_ptr()) {
984 node_->throw_invalid_obj_exception(
typeName(rcp_obj),
985 this, node_, rcp_obj.access_private_ptr() );
989 template<
class RCPType>
993 assert_valid_ptr(rcp_obj);
997 const void* get_base_obj_map_key_void_ptr()
const
1000 return node_->get_base_obj_map_key_void_ptr();
1009 bool attemptConvertWeakToStrong() {
1010 if (node_->attemptIncrementStrongCountFromNonZeroValue()) {
1012 node_->deincr_count(RCP_WEAK);
1014 strength_ = RCP_STRONG;
1022 node_->incr_count(strength_);
1024 inline void unbind()
1027 if(strength_ == RCP_STRONG) {
1029 if (node_->deincr_count(RCP_STRONG) == 0) {
1033 if( node_->deincr_count(RCP_WEAK) == 0) {
1038 else if(node_->deincr_count(RCP_WEAK) == 0) {
1043 void unbindOneStrong();
1044 void unbindOneTotal();
1092 node_->has_ownership(
false);
1093 node_->delete_obj();
1120 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1122 class SetTracingActiveNodesStack {
1124 SetTracingActiveNodesStack()
1125 {RCPNodeTracer::setTracingActiveRCPNodes(
true);}
1126 ~SetTracingActiveNodesStack()
1127 {RCPNodeTracer::setTracingActiveRCPNodes(
false);}
1130 # define SET_RCPNODE_TRACING() Teuchos::SetTracingActiveNodesStack setTracingActiveNodesStack;
1134 # define SET_RCPNODE_TRACING() (void)0
1136 #endif // defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
1142 #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'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
void pre_delete_extra_data()
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.
bool has_ownership() const
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.
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.
RCPNodeThrowDeleter(RCPNode *node)
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.
RCPNodeHandle(RCPNodeHandle &&node_ref)
Move constructor.
Handle class that manages the RCPNode'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.
~RCPNodeHandle()
Destructor.
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's RCPNode...
Deletes a (non-owning) RCPNode but not it'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...
static std::string name()
std::string typeName(const T &t)
Template function for returning the concrete type name of a passed-in object.