1 #if !defined(__OBJECT_H)
2 #define __OBJECT_H
3 
4 #include <atomic>
5 #include "constructor_stats.h"
6 
7 /// Reference counted object base class
8 class Object {
9 public:
10     /// Default constructor
Object()11     Object() { print_default_created(this); }
12 
13     /// Copy constructor
Object(const Object &)14     Object(const Object &) : m_refCount(0) { print_copy_created(this); }
15 
16     /// Return the current reference count
getRefCount()17     int getRefCount() const { return m_refCount; };
18 
19     /// Increase the object's reference count by one
incRef()20     void incRef() const { ++m_refCount; }
21 
22     /** \brief Decrease the reference count of
23      * the object and possibly deallocate it.
24      *
25      * The object will automatically be deallocated once
26      * the reference count reaches zero.
27      */
28     void decRef(bool dealloc = true) const {
29         --m_refCount;
30         if (m_refCount == 0 && dealloc)
31             delete this;
32         else if (m_refCount < 0)
33             throw std::runtime_error("Internal error: reference count < 0!");
34     }
35 
36     virtual std::string toString() const = 0;
37 protected:
38     /** \brief Virtual protected deconstructor.
39      * (Will only be called by \ref ref)
40      */
~Object()41     virtual ~Object() { print_destroyed(this); }
42 private:
43     mutable std::atomic<int> m_refCount { 0 };
44 };
45 
46 // Tag class used to track constructions of ref objects.  When we track constructors, below, we
47 // track and print out the actual class (e.g. ref<MyObject>), and *also* add a fake tracker for
48 // ref_tag.  This lets us check that the total number of ref<Anything> constructors/destructors is
49 // correct without having to check each individual ref<Whatever> type individually.
50 class ref_tag {};
51 
52 /**
53  * \brief Reference counting helper
54  *
55  * The \a ref refeference template is a simple wrapper to store a
56  * pointer to an object. It takes care of increasing and decreasing
57  * the reference count of the object. When the last reference goes
58  * out of scope, the associated object will be deallocated.
59  *
60  * \ingroup libcore
61  */
62 template <typename T> class ref {
63 public:
64     /// Create a nullptr reference
ref()65     ref() : m_ptr(nullptr) { print_default_created(this); track_default_created((ref_tag*) this); }
66 
67     /// Construct a reference from a pointer
ref(T * ptr)68     ref(T *ptr) : m_ptr(ptr) {
69         if (m_ptr) ((Object *) m_ptr)->incRef();
70 
71         print_created(this, "from pointer", m_ptr); track_created((ref_tag*) this, "from pointer");
72 
73     }
74 
75     /// Copy constructor
ref(const ref & r)76     ref(const ref &r) : m_ptr(r.m_ptr) {
77         if (m_ptr)
78             ((Object *) m_ptr)->incRef();
79 
80         print_copy_created(this, "with pointer", m_ptr); track_copy_created((ref_tag*) this);
81     }
82 
83     /// Move constructor
ref(ref && r)84     ref(ref &&r) : m_ptr(r.m_ptr) {
85         r.m_ptr = nullptr;
86 
87         print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
88     }
89 
90     /// Destroy this reference
~ref()91     ~ref() {
92         if (m_ptr)
93             ((Object *) m_ptr)->decRef();
94 
95         print_destroyed(this); track_destroyed((ref_tag*) this);
96     }
97 
98     /// Move another reference into the current one
99     ref& operator=(ref&& r) {
100         print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
101 
102         if (*this == r)
103             return *this;
104         if (m_ptr)
105             ((Object *) m_ptr)->decRef();
106         m_ptr = r.m_ptr;
107         r.m_ptr = nullptr;
108         return *this;
109     }
110 
111     /// Overwrite this reference with another reference
112     ref& operator=(const ref& r) {
113         print_copy_assigned(this, "pointer", r.m_ptr); track_copy_assigned((ref_tag*) this);
114 
115         if (m_ptr == r.m_ptr)
116             return *this;
117         if (m_ptr)
118             ((Object *) m_ptr)->decRef();
119         m_ptr = r.m_ptr;
120         if (m_ptr)
121             ((Object *) m_ptr)->incRef();
122         return *this;
123     }
124 
125     /// Overwrite this reference with a pointer to another object
126     ref& operator=(T *ptr) {
127         print_values(this, "assigned pointer"); track_values((ref_tag*) this, "assigned pointer");
128 
129         if (m_ptr == ptr)
130             return *this;
131         if (m_ptr)
132             ((Object *) m_ptr)->decRef();
133         m_ptr = ptr;
134         if (m_ptr)
135             ((Object *) m_ptr)->incRef();
136         return *this;
137     }
138 
139     /// Compare this reference with another reference
140     bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
141 
142     /// Compare this reference with another reference
143     bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
144 
145     /// Compare this reference with a pointer
146     bool operator==(const T* ptr) const { return m_ptr == ptr; }
147 
148     /// Compare this reference with a pointer
149     bool operator!=(const T* ptr) const { return m_ptr != ptr; }
150 
151     /// Access the object referenced by this reference
152     T* operator->() { return m_ptr; }
153 
154     /// Access the object referenced by this reference
155     const T* operator->() const { return m_ptr; }
156 
157     /// Return a C++ reference to the referenced object
158     T& operator*() { return *m_ptr; }
159 
160     /// Return a const C++ reference to the referenced object
161     const T& operator*() const { return *m_ptr; }
162 
163     /// Return a pointer to the referenced object
164     operator T* () { return m_ptr; }
165 
166     /// Return a const pointer to the referenced object
get_ptr()167     T* get_ptr() { return m_ptr; }
168 
169     /// Return a pointer to the referenced object
get_ptr()170     const T* get_ptr() const { return m_ptr; }
171 private:
172     T *m_ptr;
173 };
174 
175 #endif /* __OBJECT_H */
176