File indexing completed on 2025-01-18 10:17:51
0001 #if !defined(__OBJECT_H)
0002 # define __OBJECT_H
0003
0004 # include "constructor_stats.h"
0005
0006 # include <atomic>
0007
0008
0009 class Object {
0010 public:
0011
0012 Object() { print_default_created(this); }
0013
0014
0015 Object(const Object &) : m_refCount(0) { print_copy_created(this); }
0016
0017
0018 int getRefCount() const { return m_refCount; };
0019
0020
0021 void incRef() const { ++m_refCount; }
0022
0023
0024
0025
0026
0027
0028
0029 void decRef(bool dealloc = true) const {
0030 --m_refCount;
0031 if (m_refCount == 0 && dealloc) {
0032 delete this;
0033 } else if (m_refCount < 0) {
0034 throw std::runtime_error("Internal error: reference count < 0!");
0035 }
0036 }
0037
0038 virtual std::string toString() const = 0;
0039
0040 protected:
0041
0042
0043
0044 virtual ~Object() { print_destroyed(this); }
0045
0046 private:
0047 mutable std::atomic<int> m_refCount{0};
0048 };
0049
0050
0051
0052
0053
0054 class ref_tag {};
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 template <typename T>
0067 class ref {
0068 public:
0069
0070 ref() : m_ptr(nullptr) {
0071 print_default_created(this);
0072 track_default_created((ref_tag *) this);
0073 }
0074
0075
0076 explicit ref(T *ptr) : m_ptr(ptr) {
0077 if (m_ptr) {
0078 ((Object *) m_ptr)->incRef();
0079 }
0080
0081 print_created(this, "from pointer", m_ptr);
0082 track_created((ref_tag *) this, "from pointer");
0083 }
0084
0085
0086 ref(const ref &r) : m_ptr(r.m_ptr) {
0087 if (m_ptr) {
0088 ((Object *) m_ptr)->incRef();
0089 }
0090
0091 print_copy_created(this, "with pointer", m_ptr);
0092 track_copy_created((ref_tag *) this);
0093 }
0094
0095
0096 ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
0097 r.m_ptr = nullptr;
0098
0099 print_move_created(this, "with pointer", m_ptr);
0100 track_move_created((ref_tag *) this);
0101 }
0102
0103
0104 ~ref() {
0105 if (m_ptr) {
0106 ((Object *) m_ptr)->decRef();
0107 }
0108
0109 print_destroyed(this);
0110 track_destroyed((ref_tag *) this);
0111 }
0112
0113
0114 ref &operator=(ref &&r) noexcept {
0115 print_move_assigned(this, "pointer", r.m_ptr);
0116 track_move_assigned((ref_tag *) this);
0117
0118 if (*this == r) {
0119 return *this;
0120 }
0121 if (m_ptr) {
0122 ((Object *) m_ptr)->decRef();
0123 }
0124 m_ptr = r.m_ptr;
0125 r.m_ptr = nullptr;
0126 return *this;
0127 }
0128
0129
0130 ref &operator=(const ref &r) {
0131 if (this == &r) {
0132 return *this;
0133 }
0134 print_copy_assigned(this, "pointer", r.m_ptr);
0135 track_copy_assigned((ref_tag *) this);
0136
0137 if (m_ptr == r.m_ptr) {
0138 return *this;
0139 }
0140 if (m_ptr) {
0141 ((Object *) m_ptr)->decRef();
0142 }
0143 m_ptr = r.m_ptr;
0144 if (m_ptr) {
0145 ((Object *) m_ptr)->incRef();
0146 }
0147 return *this;
0148 }
0149
0150
0151 ref &operator=(T *ptr) {
0152 print_values(this, "assigned pointer");
0153 track_values((ref_tag *) this, "assigned pointer");
0154
0155 if (m_ptr == ptr) {
0156 return *this;
0157 }
0158 if (m_ptr) {
0159 ((Object *) m_ptr)->decRef();
0160 }
0161 m_ptr = ptr;
0162 if (m_ptr) {
0163 ((Object *) m_ptr)->incRef();
0164 }
0165 return *this;
0166 }
0167
0168
0169 bool operator==(const ref &r) const { return m_ptr == r.m_ptr; }
0170
0171
0172 bool operator!=(const ref &r) const { return m_ptr != r.m_ptr; }
0173
0174
0175 bool operator==(const T *ptr) const { return m_ptr == ptr; }
0176
0177
0178 bool operator!=(const T *ptr) const { return m_ptr != ptr; }
0179
0180
0181 T *operator->() { return m_ptr; }
0182
0183
0184 const T *operator->() const { return m_ptr; }
0185
0186
0187 T &operator*() { return *m_ptr; }
0188
0189
0190 const T &operator*() const { return *m_ptr; }
0191
0192
0193 explicit operator T *() { return m_ptr; }
0194
0195
0196 T *get_ptr() { return m_ptr; }
0197
0198
0199 const T *get_ptr() const { return m_ptr; }
0200
0201 private:
0202 T *m_ptr;
0203 };
0204
0205 #endif