Line data Source code
1 : /** 2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org> 3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev> 4 : 5 : Permission is hereby granted, free of charge, to any person obtaining a copy 6 : of this software and associated documentation files (the "Software"), to deal 7 : in the Software without restriction, including without limitation the rights 8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 : copies of the Software, and to permit persons to whom the Software is 10 : furnished to do so, subject to the following conditions: 11 : 12 : The above copyright notice and this permission notice shall be included in 13 : all copies or substantial portions of the Software. 14 : 15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 : THE SOFTWARE. 22 : **/ 23 : 24 : #ifndef STAPPLER_CORE_UTILS_SPREF_H_ 25 : #define STAPPLER_CORE_UTILS_SPREF_H_ 26 : 27 : #include "SPTime.h" 28 : 29 : // enable Ref debug mode to track retain/release sources 30 : #ifndef SP_REF_DEBUG 31 : #define SP_REF_DEBUG 0 32 : #endif 33 : 34 : namespace STAPPLER_VERSIONIZED stappler { 35 : 36 : struct AtomicCounter { 37 10051766 : AtomicCounter() { _count.store(1); } 38 : 39 51565407 : void increment() { ++ _count; } 40 120863898 : bool decrement() { if (_count.fetch_sub(1) == 1) { return true; } return false; } 41 129068 : uint32_t get() const { return _count.load(); } 42 : 43 : std::atomic<uint32_t> _count; 44 : }; 45 : 46 : template <typename Interface> 47 : class RefBase : public Interface::AllocBaseType { 48 : public: 49 : using InterfaceType = Interface; 50 : 51 : #if SP_REF_DEBUG 52 : virtual uint64_t retain(); 53 : virtual void release(uint64_t id); 54 : 55 : void foreachBacktrace(const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &) const; 56 : 57 : #else 58 51590277 : uint64_t retain() { _counter.increment(); return 0; } 59 60471972 : void release(uint64_t id) { if (_counter.decrement()) { delete this; } } 60 : #endif 61 : 62 64534 : uint32_t getReferenceCount() const { return _counter.get(); } 63 : 64 10052837 : virtual ~RefBase() { } 65 : 66 : protected: 67 10051936 : RefBase() { } 68 : 69 : #if SP_REF_DEBUG 70 : virtual bool isRetainTrackerEnabled() const { 71 : return false; 72 : } 73 : #endif 74 : 75 : AtomicCounter _counter; 76 : }; 77 : 78 : namespace memleak { 79 : 80 : uint64_t getNextRefId(); 81 : uint64_t retainBacktrace(const RefBase<memory::StandartInterface> *); 82 : void releaseBacktrace(const RefBase<memory::StandartInterface> *, uint64_t); 83 : void foreachBacktrace(const RefBase<memory::StandartInterface> *, 84 : const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &); 85 : 86 : uint64_t retainBacktrace(const RefBase<memory::PoolInterface> *); 87 : void releaseBacktrace(const RefBase<memory::PoolInterface> *, uint64_t); 88 : void foreachBacktrace(const RefBase<memory::PoolInterface> *, 89 : const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &); 90 : } 91 : 92 : template <typename Base> 93 : class RcBase { 94 : public: 95 : using Type = typename std::remove_cv<Base>::type; 96 : using Self = RcBase<Base>; 97 : using Pointer = Type *; 98 : 99 : template <class... Args> 100 4698985 : static inline Self create(Args && ... args) { 101 8302568 : auto pRet = new Type(); 102 4699042 : if (pRet->init(std::forward<Args>(args)...)) { 103 4699005 : return Self(pRet, true); // unsafe assignment 104 : } else { 105 0 : delete pRet; 106 0 : return Self(nullptr); 107 : } 108 : } 109 : 110 960860 : static inline Self alloc() { 111 1921636 : return Self(new Type(), true); 112 : } 113 : 114 : template <class... Args> 115 600337 : static inline Self alloc(Args && ... args) { 116 600337 : return Self(new Type(std::forward<Args>(args)...), true); 117 : } 118 : 119 438785095 : inline RcBase() : _ptr(nullptr) { } 120 1056905 : inline RcBase(const nullptr_t &) : _ptr(nullptr) { } 121 9364507 : inline RcBase(const Pointer &value) : _ptr(value) { doRetain(); } 122 13573449 : inline RcBase(const Self &v) { _ptr = v._ptr; doRetain(); } 123 14826825 : inline RcBase(Self &&v) { 124 14826825 : _ptr = v._ptr; v._ptr = nullptr; 125 : #if SP_REF_DEBUG 126 : _id = v._id; v._id = 0; 127 : #endif 128 14826825 : } 129 : 130 2413295 : inline RcBase & operator = (const nullptr_t &) { 131 2413295 : doRelease(); 132 2413381 : _ptr = nullptr; 133 : #if SP_REF_DEBUG 134 : _id = 0; 135 : #endif 136 2413381 : return *this; 137 : } 138 : 139 : template <typename B, typename std::enable_if<std::is_convertible<B*, Base *>{}>::type* = nullptr> 140 1887 : inline RcBase & operator = (const RcBase<B> &value) { set(value); return *this; } 141 : 142 462043 : inline RcBase & operator = (const Pointer &value) { set(value); return *this; } 143 3989720 : inline RcBase & operator = (const Self &v) { set(v._ptr); return *this; } 144 224284901 : inline RcBase & operator = (Self &&v) { 145 224284901 : doRelease(); 146 224279957 : _ptr = v._ptr; v._ptr = nullptr; 147 : #if SP_REF_DEBUG 148 : _id = v._id; v._id = 0; 149 : #endif 150 224279957 : return *this; 151 : } 152 : 153 231328096 : inline ~RcBase() { doRelease(); _ptr = nullptr; } 154 : 155 4409906 : inline void set(const Pointer &value) { 156 4409906 : _ptr = doSwap(value); 157 4409907 : } 158 : 159 24979244 : inline Base *get() const { 160 : #if SP_REF_DEBUG 161 : assert(_ptr); 162 : #endif 163 24979244 : return _ptr; 164 : } 165 : 166 16232322 : inline operator Base * () const { return get(); } 167 468168195 : inline explicit operator bool () const { return _ptr != nullptr; } 168 : 169 : template <typename B, typename std::enable_if<std::is_convertible<Base *, B*>{}>::type* = nullptr> 170 5096923 : inline operator RcBase<B> () { return RcBase<B>(static_cast<B *>(get())); } 171 : 172 : inline void swap(Self & v) { auto ptr = _ptr; _ptr = v._ptr; v._ptr = ptr; } 173 : 174 143875478 : inline Base * operator->() const { return _ptr; } 175 : 176 : template <typename Target> 177 271059 : inline RcBase<Target> cast() const { 178 271059 : if (auto v = dynamic_cast<Target *>(_ptr)) { 179 270274 : return RcBase<Target>(v); 180 : } 181 787 : return RcBase<Target>(nullptr); 182 : } 183 : 184 10439 : inline bool operator == (const Self & other) const { return _ptr == other._ptr; } 185 8038 : inline bool operator == (const Base * & other) const { return _ptr == other; } 186 2500376 : inline bool operator == (typename std::remove_const<Base>::type * other) const { return _ptr == other; } 187 14638 : inline bool operator == (const std::nullptr_t other) const { return _ptr == other; } 188 : 189 69162 : inline bool operator != (const Self & other) const { return _ptr != other._ptr; } 190 : inline bool operator != (const Base * & other) const { return _ptr != other; } 191 226861 : inline bool operator != (typename std::remove_const<Base>::type * other) const { return _ptr != other; } 192 1464 : inline bool operator != (const std::nullptr_t other) const { return _ptr != other; } 193 : 194 : inline bool operator > (const Self & other) const { return _ptr > other._ptr; } 195 : inline bool operator > (const Base * other) const { return _ptr > other; } 196 : inline bool operator > (typename std::remove_const<Base>::type * other) const { return _ptr > other; } 197 : inline bool operator > (const std::nullptr_t other) const { return _ptr > other; } 198 : 199 9993800 : inline bool operator < (const Self & other) const { return _ptr < other._ptr; } 200 812 : inline bool operator < (const Base * other) const { return _ptr < other; } 201 : inline bool operator < (typename std::remove_const<Base>::type * other) const { return _ptr < other; } 202 : inline bool operator < (const std::nullptr_t other) const { return _ptr < other; } 203 : 204 : inline bool operator >= (const Self & other) const { return _ptr >= other._ptr; } 205 : inline bool operator >= (const Base * other) const { return _ptr >= other; } 206 : inline bool operator >= (typename std::remove_const<Base>::type * other) const { return _ptr >= other; } 207 : inline bool operator >= (const std::nullptr_t other) const { return _ptr >= other; } 208 : 209 : inline bool operator <= (const Self & other) const { return _ptr <= other._ptr; } 210 : inline bool operator <= (const Base * other) const { return _ptr <= other; } 211 : inline bool operator <= (typename std::remove_const<Base>::type * other) const { return _ptr <= other; } 212 : inline bool operator <= (const std::nullptr_t other) const { return _ptr <= other; } 213 : 214 : #if SP_REF_DEBUG 215 : uint64_t getId() const { return _id; } 216 : #endif 217 : private: 218 19899190 : inline void doRetain() { 219 : #if SP_REF_DEBUG 220 : if (_ptr) { _id = _ptr->retain(); } 221 : #else 222 19899190 : if (_ptr) { _ptr->retain(); } 223 : #endif 224 19901775 : } 225 : 226 327312258 : inline void doRelease() { 227 : #if SP_REF_DEBUG 228 : if (_ptr) { _ptr->release(_id); } 229 : #else 230 327312258 : if (_ptr) { _ptr->release(0); } 231 : #endif 232 327318149 : } 233 : 234 4409905 : inline Pointer doSwap(Pointer value) { 235 : #if SP_REF_DEBUG 236 : uint64_t id = 0; 237 : if (value) { id = value->retain(); } 238 : if (_ptr) { _ptr->release(_id); } 239 : _id = id; 240 : return value; 241 : #else 242 4409905 : if (value) { value->retain(); } 243 4409914 : if (_ptr) { _ptr->release(0); } 244 4409910 : return value; 245 : #endif 246 : } 247 : 248 : // unsafe 249 5761488 : inline RcBase(Pointer value, bool v) : _ptr(value) { } 250 : 251 : Pointer _ptr = nullptr; 252 : #if SP_REF_DEBUG 253 : uint64_t _id = 0; 254 : #endif 255 : }; 256 : 257 : template <typename T> 258 : using Rc = RcBase<T>; 259 : 260 : #if SP_REF_DEBUG 261 : 262 : template <typename Interface> 263 : uint64_t RefBase<Interface>::retain() { 264 : _counter.increment(); 265 : if (isRetainTrackerEnabled()) { 266 : return memleak::retainBacktrace(this); 267 : } 268 : return 0; 269 : } 270 : 271 : template <typename Interface> 272 : void RefBase<Interface>::release(uint64_t v) { 273 : if (isRetainTrackerEnabled()) { 274 : memleak::releaseBacktrace(this, v); 275 : } 276 : if (_counter.decrement()) { 277 : delete this; 278 : } 279 : } 280 : 281 : template <typename Interface> 282 : void RefBase<Interface>::foreachBacktrace(const Callback<void(uint64_t, Time, const std::vector<std::string> &)> &cb) const { 283 : memleak::foreachBacktrace(this, cb); 284 : } 285 : 286 : #endif 287 : 288 : } 289 : 290 : namespace STAPPLER_VERSIONIZED stappler::mem_std { 291 : 292 : using Ref = RefBase<memory::StandartInterface>; 293 : 294 : } 295 : 296 : namespace STAPPLER_VERSIONIZED stappler::mem_pool { 297 : 298 : using Ref = RefBase<memory::PoolInterface>; 299 : 300 : } 301 : 302 : #endif /* STAPPLER_CORE_UTILS_REF_SPREF_H_ */