object.h revision 11986
111986Sandreas.sandberg@arm.com#if !defined(__OBJECT_H) 211986Sandreas.sandberg@arm.com#define __OBJECT_H 311986Sandreas.sandberg@arm.com 411986Sandreas.sandberg@arm.com#include <atomic> 511986Sandreas.sandberg@arm.com#include "constructor_stats.h" 611986Sandreas.sandberg@arm.com 711986Sandreas.sandberg@arm.com/// Reference counted object base class 811986Sandreas.sandberg@arm.comclass Object { 911986Sandreas.sandberg@arm.compublic: 1011986Sandreas.sandberg@arm.com /// Default constructor 1111986Sandreas.sandberg@arm.com Object() { print_default_created(this); } 1211986Sandreas.sandberg@arm.com 1311986Sandreas.sandberg@arm.com /// Copy constructor 1411986Sandreas.sandberg@arm.com Object(const Object &) : m_refCount(0) { print_copy_created(this); } 1511986Sandreas.sandberg@arm.com 1611986Sandreas.sandberg@arm.com /// Return the current reference count 1711986Sandreas.sandberg@arm.com int getRefCount() const { return m_refCount; }; 1811986Sandreas.sandberg@arm.com 1911986Sandreas.sandberg@arm.com /// Increase the object's reference count by one 2011986Sandreas.sandberg@arm.com void incRef() const { ++m_refCount; } 2111986Sandreas.sandberg@arm.com 2211986Sandreas.sandberg@arm.com /** \brief Decrease the reference count of 2311986Sandreas.sandberg@arm.com * the object and possibly deallocate it. 2411986Sandreas.sandberg@arm.com * 2511986Sandreas.sandberg@arm.com * The object will automatically be deallocated once 2611986Sandreas.sandberg@arm.com * the reference count reaches zero. 2711986Sandreas.sandberg@arm.com */ 2811986Sandreas.sandberg@arm.com void decRef(bool dealloc = true) const { 2911986Sandreas.sandberg@arm.com --m_refCount; 3011986Sandreas.sandberg@arm.com if (m_refCount == 0 && dealloc) 3111986Sandreas.sandberg@arm.com delete this; 3211986Sandreas.sandberg@arm.com else if (m_refCount < 0) 3311986Sandreas.sandberg@arm.com throw std::runtime_error("Internal error: reference count < 0!"); 3411986Sandreas.sandberg@arm.com } 3511986Sandreas.sandberg@arm.com 3611986Sandreas.sandberg@arm.com virtual std::string toString() const = 0; 3711986Sandreas.sandberg@arm.comprotected: 3811986Sandreas.sandberg@arm.com /** \brief Virtual protected deconstructor. 3911986Sandreas.sandberg@arm.com * (Will only be called by \ref ref) 4011986Sandreas.sandberg@arm.com */ 4111986Sandreas.sandberg@arm.com virtual ~Object() { print_destroyed(this); } 4211986Sandreas.sandberg@arm.comprivate: 4311986Sandreas.sandberg@arm.com mutable std::atomic<int> m_refCount { 0 }; 4411986Sandreas.sandberg@arm.com}; 4511986Sandreas.sandberg@arm.com 4611986Sandreas.sandberg@arm.com// Tag class used to track constructions of ref objects. When we track constructors, below, we 4711986Sandreas.sandberg@arm.com// track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for 4811986Sandreas.sandberg@arm.com// ref_tag. This lets us check that the total number of ref<Anything> constructors/destructors is 4911986Sandreas.sandberg@arm.com// correct without having to check each individual ref<Whatever> type individually. 5011986Sandreas.sandberg@arm.comclass ref_tag {}; 5111986Sandreas.sandberg@arm.com 5211986Sandreas.sandberg@arm.com/** 5311986Sandreas.sandberg@arm.com * \brief Reference counting helper 5411986Sandreas.sandberg@arm.com * 5511986Sandreas.sandberg@arm.com * The \a ref refeference template is a simple wrapper to store a 5611986Sandreas.sandberg@arm.com * pointer to an object. It takes care of increasing and decreasing 5711986Sandreas.sandberg@arm.com * the reference count of the object. When the last reference goes 5811986Sandreas.sandberg@arm.com * out of scope, the associated object will be deallocated. 5911986Sandreas.sandberg@arm.com * 6011986Sandreas.sandberg@arm.com * \ingroup libcore 6111986Sandreas.sandberg@arm.com */ 6211986Sandreas.sandberg@arm.comtemplate <typename T> class ref { 6311986Sandreas.sandberg@arm.compublic: 6411986Sandreas.sandberg@arm.com /// Create a nullptr reference 6511986Sandreas.sandberg@arm.com ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); } 6611986Sandreas.sandberg@arm.com 6711986Sandreas.sandberg@arm.com /// Construct a reference from a pointer 6811986Sandreas.sandberg@arm.com ref(T *ptr) : m_ptr(ptr) { 6911986Sandreas.sandberg@arm.com if (m_ptr) ((Object *) m_ptr)->incRef(); 7011986Sandreas.sandberg@arm.com 7111986Sandreas.sandberg@arm.com print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer"); 7211986Sandreas.sandberg@arm.com 7311986Sandreas.sandberg@arm.com } 7411986Sandreas.sandberg@arm.com 7511986Sandreas.sandberg@arm.com /// Copy constructor 7611986Sandreas.sandberg@arm.com ref(const ref &r) : m_ptr(r.m_ptr) { 7711986Sandreas.sandberg@arm.com if (m_ptr) 7811986Sandreas.sandberg@arm.com ((Object *) m_ptr)->incRef(); 7911986Sandreas.sandberg@arm.com 8011986Sandreas.sandberg@arm.com print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this); 8111986Sandreas.sandberg@arm.com } 8211986Sandreas.sandberg@arm.com 8311986Sandreas.sandberg@arm.com /// Move constructor 8411986Sandreas.sandberg@arm.com ref(ref &&r) : m_ptr(r.m_ptr) { 8511986Sandreas.sandberg@arm.com r.m_ptr = nullptr; 8611986Sandreas.sandberg@arm.com 8711986Sandreas.sandberg@arm.com print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); 8811986Sandreas.sandberg@arm.com } 8911986Sandreas.sandberg@arm.com 9011986Sandreas.sandberg@arm.com /// Destroy this reference 9111986Sandreas.sandberg@arm.com ~ref() { 9211986Sandreas.sandberg@arm.com if (m_ptr) 9311986Sandreas.sandberg@arm.com ((Object *) m_ptr)->decRef(); 9411986Sandreas.sandberg@arm.com 9511986Sandreas.sandberg@arm.com print_destroyed(this); track_destroyed((ref_tag*) this); 9611986Sandreas.sandberg@arm.com } 9711986Sandreas.sandberg@arm.com 9811986Sandreas.sandberg@arm.com /// Move another reference into the current one 9911986Sandreas.sandberg@arm.com ref& operator=(ref&& r) { 10011986Sandreas.sandberg@arm.com print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); 10111986Sandreas.sandberg@arm.com 10211986Sandreas.sandberg@arm.com if (*this == r) 10311986Sandreas.sandberg@arm.com return *this; 10411986Sandreas.sandberg@arm.com if (m_ptr) 10511986Sandreas.sandberg@arm.com ((Object *) m_ptr)->decRef(); 10611986Sandreas.sandberg@arm.com m_ptr = r.m_ptr; 10711986Sandreas.sandberg@arm.com r.m_ptr = nullptr; 10811986Sandreas.sandberg@arm.com return *this; 10911986Sandreas.sandberg@arm.com } 11011986Sandreas.sandberg@arm.com 11111986Sandreas.sandberg@arm.com /// Overwrite this reference with another reference 11211986Sandreas.sandberg@arm.com ref& operator=(const ref& r) { 11311986Sandreas.sandberg@arm.com print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this); 11411986Sandreas.sandberg@arm.com 11511986Sandreas.sandberg@arm.com if (m_ptr == r.m_ptr) 11611986Sandreas.sandberg@arm.com return *this; 11711986Sandreas.sandberg@arm.com if (m_ptr) 11811986Sandreas.sandberg@arm.com ((Object *) m_ptr)->decRef(); 11911986Sandreas.sandberg@arm.com m_ptr = r.m_ptr; 12011986Sandreas.sandberg@arm.com if (m_ptr) 12111986Sandreas.sandberg@arm.com ((Object *) m_ptr)->incRef(); 12211986Sandreas.sandberg@arm.com return *this; 12311986Sandreas.sandberg@arm.com } 12411986Sandreas.sandberg@arm.com 12511986Sandreas.sandberg@arm.com /// Overwrite this reference with a pointer to another object 12611986Sandreas.sandberg@arm.com ref& operator=(T *ptr) { 12711986Sandreas.sandberg@arm.com print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer"); 12811986Sandreas.sandberg@arm.com 12911986Sandreas.sandberg@arm.com if (m_ptr == ptr) 13011986Sandreas.sandberg@arm.com return *this; 13111986Sandreas.sandberg@arm.com if (m_ptr) 13211986Sandreas.sandberg@arm.com ((Object *) m_ptr)->decRef(); 13311986Sandreas.sandberg@arm.com m_ptr = ptr; 13411986Sandreas.sandberg@arm.com if (m_ptr) 13511986Sandreas.sandberg@arm.com ((Object *) m_ptr)->incRef(); 13611986Sandreas.sandberg@arm.com return *this; 13711986Sandreas.sandberg@arm.com } 13811986Sandreas.sandberg@arm.com 13911986Sandreas.sandberg@arm.com /// Compare this reference with another reference 14011986Sandreas.sandberg@arm.com bool operator==(const ref &r) const { return m_ptr == r.m_ptr; } 14111986Sandreas.sandberg@arm.com 14211986Sandreas.sandberg@arm.com /// Compare this reference with another reference 14311986Sandreas.sandberg@arm.com bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; } 14411986Sandreas.sandberg@arm.com 14511986Sandreas.sandberg@arm.com /// Compare this reference with a pointer 14611986Sandreas.sandberg@arm.com bool operator==(const T* ptr) const { return m_ptr == ptr; } 14711986Sandreas.sandberg@arm.com 14811986Sandreas.sandberg@arm.com /// Compare this reference with a pointer 14911986Sandreas.sandberg@arm.com bool operator!=(const T* ptr) const { return m_ptr != ptr; } 15011986Sandreas.sandberg@arm.com 15111986Sandreas.sandberg@arm.com /// Access the object referenced by this reference 15211986Sandreas.sandberg@arm.com T* operator->() { return m_ptr; } 15311986Sandreas.sandberg@arm.com 15411986Sandreas.sandberg@arm.com /// Access the object referenced by this reference 15511986Sandreas.sandberg@arm.com const T* operator->() const { return m_ptr; } 15611986Sandreas.sandberg@arm.com 15711986Sandreas.sandberg@arm.com /// Return a C++ reference to the referenced object 15811986Sandreas.sandberg@arm.com T& operator*() { return *m_ptr; } 15911986Sandreas.sandberg@arm.com 16011986Sandreas.sandberg@arm.com /// Return a const C++ reference to the referenced object 16111986Sandreas.sandberg@arm.com const T& operator*() const { return *m_ptr; } 16211986Sandreas.sandberg@arm.com 16311986Sandreas.sandberg@arm.com /// Return a pointer to the referenced object 16411986Sandreas.sandberg@arm.com operator T* () { return m_ptr; } 16511986Sandreas.sandberg@arm.com 16611986Sandreas.sandberg@arm.com /// Return a const pointer to the referenced object 16711986Sandreas.sandberg@arm.com T* get() { return m_ptr; } 16811986Sandreas.sandberg@arm.com 16911986Sandreas.sandberg@arm.com /// Return a pointer to the referenced object 17011986Sandreas.sandberg@arm.com const T* get() const { return m_ptr; } 17111986Sandreas.sandberg@arm.comprivate: 17211986Sandreas.sandberg@arm.com T *m_ptr; 17311986Sandreas.sandberg@arm.com}; 17411986Sandreas.sandberg@arm.com 17511986Sandreas.sandberg@arm.com#endif /* __OBJECT_H */ 176