1 /* 2 ============================================================================== 3 4 This file is part of the Water library. 5 Copyright (c) 2016 ROLI Ltd. 6 Copyright (C) 2017 Filipe Coelho <falktx@falktx.com> 7 8 Permission is granted to use this software under the terms of the ISC license 9 http://www.isc.org/downloads/software-support-policy/isc-license/ 10 11 Permission to use, copy, modify, and/or distribute this software for any 12 purpose with or without fee is hereby granted, provided that the above 13 copyright notice and this permission notice appear in all copies. 14 15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD 16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, 18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 OF THIS SOFTWARE. 22 23 ============================================================================== 24 */ 25 26 #ifndef WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED 27 #define WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED 28 29 #include "Atomic.h" 30 31 namespace water { 32 33 //============================================================================== 34 /** 35 A base class which provides methods for reference-counting. 36 37 To add reference-counting to a class, derive it from this class, and 38 use the ReferenceCountedObjectPtr class to point to it. 39 40 e.g. @code 41 class MyClass : public ReferenceCountedObject 42 { 43 void foo(); 44 45 // This is a neat way of declaring a typedef for a pointer class, 46 // rather than typing out the full templated name each time.. 47 typedef ReferenceCountedObjectPtr<MyClass> Ptr; 48 }; 49 50 MyClass::Ptr p = new MyClass(); 51 MyClass::Ptr p2 = p; 52 p = nullptr; 53 p2->foo(); 54 @endcode 55 56 Once a new ReferenceCountedObject has been assigned to a pointer, be 57 careful not to delete the object manually. 58 59 This class uses an Atomic<int> value to hold the reference count, so that it 60 the pointers can be passed between threads safely. For a faster but non-thread-safe 61 version, use SingleThreadedReferenceCountedObject instead. 62 63 @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject 64 */ 65 class ReferenceCountedObject 66 { 67 public: 68 //============================================================================== 69 /** Increments the object's reference count. 70 71 This is done automatically by the smart pointer, but is public just 72 in case it's needed for nefarious purposes. 73 */ incReferenceCount()74 void incReferenceCount() noexcept 75 { 76 ++refCount; 77 } 78 79 /** Decreases the object's reference count. 80 If the count gets to zero, the object will be deleted. 81 */ decReferenceCount()82 void decReferenceCount() noexcept 83 { 84 wassert (getReferenceCount() > 0); 85 86 if (--refCount == 0) 87 delete this; 88 } 89 90 /** Decreases the object's reference count. 91 If the count gets to zero, the object will not be deleted, but this method 92 will return true, allowing the caller to take care of deletion. 93 */ decReferenceCountWithoutDeleting()94 bool decReferenceCountWithoutDeleting() noexcept 95 { 96 wassert (getReferenceCount() > 0); 97 return --refCount == 0; 98 } 99 100 /** Returns the object's current reference count. */ getReferenceCount()101 int getReferenceCount() const noexcept { return refCount.get(); } 102 103 104 protected: 105 //============================================================================== 106 /** Creates the reference-counted object (with an initial ref count of zero). */ ReferenceCountedObject()107 ReferenceCountedObject() 108 : refCount() {} 109 110 /** Destructor. */ ~ReferenceCountedObject()111 virtual ~ReferenceCountedObject() 112 { 113 // it's dangerous to delete an object that's still referenced by something else! 114 wassert (getReferenceCount() == 0); 115 } 116 117 /** Resets the reference count to zero without deleting the object. 118 You should probably never need to use this! 119 */ resetReferenceCount()120 void resetReferenceCount() noexcept 121 { 122 refCount = 0; 123 } 124 125 private: 126 //============================================================================== 127 Atomic<int> refCount; 128 129 CARLA_DECLARE_NON_COPY_CLASS (ReferenceCountedObject) 130 }; 131 132 133 //============================================================================== 134 /** 135 Adds reference-counting to an object. 136 137 This is effectively a version of the ReferenceCountedObject class, but which 138 uses a non-atomic counter, and so is not thread-safe (but which will be more 139 efficient). 140 For more details on how to use it, see the ReferenceCountedObject class notes. 141 142 @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray 143 */ 144 class SingleThreadedReferenceCountedObject 145 { 146 public: 147 //============================================================================== 148 /** Increments the object's reference count. 149 150 This is done automatically by the smart pointer, but is public just 151 in case it's needed for nefarious purposes. 152 */ incReferenceCount()153 void incReferenceCount() noexcept 154 { 155 ++refCount; 156 } 157 158 /** Decreases the object's reference count. 159 If the count gets to zero, the object will be deleted. 160 */ decReferenceCount()161 void decReferenceCount() noexcept 162 { 163 wassert (getReferenceCount() > 0); 164 165 if (--refCount == 0) 166 delete this; 167 } 168 169 /** Decreases the object's reference count. 170 If the count gets to zero, the object will not be deleted, but this method 171 will return true, allowing the caller to take care of deletion. 172 */ decReferenceCountWithoutDeleting()173 bool decReferenceCountWithoutDeleting() noexcept 174 { 175 wassert (getReferenceCount() > 0); 176 return --refCount == 0; 177 } 178 179 /** Returns the object's current reference count. */ getReferenceCount()180 int getReferenceCount() const noexcept { return refCount; } 181 182 183 protected: 184 //============================================================================== 185 /** Creates the reference-counted object (with an initial ref count of zero). */ SingleThreadedReferenceCountedObject()186 SingleThreadedReferenceCountedObject() : refCount (0) {} 187 188 /** Destructor. */ ~SingleThreadedReferenceCountedObject()189 virtual ~SingleThreadedReferenceCountedObject() 190 { 191 // it's dangerous to delete an object that's still referenced by something else! 192 wassert (getReferenceCount() == 0); 193 } 194 195 private: 196 //============================================================================== 197 int refCount; 198 199 CARLA_DECLARE_NON_COPY_CLASS (SingleThreadedReferenceCountedObject) 200 }; 201 202 203 //============================================================================== 204 /** 205 A smart-pointer class which points to a reference-counted object. 206 207 The template parameter specifies the class of the object you want to point to - the easiest 208 way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject 209 or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable 210 class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and 211 decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods 212 should behave. 213 214 When using this class, you'll probably want to create a typedef to abbreviate the full 215 templated name - e.g. 216 @code 217 struct MyClass : public ReferenceCountedObject 218 { 219 typedef ReferenceCountedObjectPtr<MyClass> Ptr; 220 ... 221 @endcode 222 223 @see ReferenceCountedObject, ReferenceCountedObjectArray 224 */ 225 template <class ReferenceCountedObjectClass> 226 class ReferenceCountedObjectPtr 227 { 228 public: 229 /** The class being referenced by this pointer. */ 230 typedef ReferenceCountedObjectClass ReferencedType; 231 232 //============================================================================== 233 /** Creates a pointer to a null object. */ ReferenceCountedObjectPtr()234 ReferenceCountedObjectPtr() noexcept 235 : referencedObject (nullptr) 236 { 237 } 238 239 /** Creates a pointer to an object. 240 This will increment the object's reference-count. 241 */ ReferenceCountedObjectPtr(ReferencedType * refCountedObject)242 ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept 243 : referencedObject (refCountedObject) 244 { 245 incIfNotNull (refCountedObject); 246 } 247 248 /** Copies another pointer. 249 This will increment the object's reference-count. 250 */ ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr & other)251 ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept 252 : referencedObject (other.referencedObject) 253 { 254 incIfNotNull (referencedObject); 255 } 256 257 /** Copies another pointer. 258 This will increment the object's reference-count (if it is non-null). 259 */ 260 template <typename Convertible> ReferenceCountedObjectPtr(const ReferenceCountedObjectPtr<Convertible> & other)261 ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept 262 : referencedObject (static_cast<ReferencedType*> (other.get())) 263 { 264 incIfNotNull (referencedObject); 265 } 266 267 /** Changes this pointer to point at a different object. 268 The reference count of the old object is decremented, and it might be 269 deleted if it hits zero. The new object's count is incremented. 270 */ 271 ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) 272 { 273 return operator= (other.referencedObject); 274 } 275 276 /** Changes this pointer to point at a different object. 277 The reference count of the old object is decremented, and it might be 278 deleted if it hits zero. The new object's count is incremented. 279 */ 280 template <typename Convertible> 281 ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other) 282 { 283 return operator= (static_cast<ReferencedType*> (other.get())); 284 } 285 286 /** Changes this pointer to point at a different object. 287 288 The reference count of the old object is decremented, and it might be 289 deleted if it hits zero. The new object's count is incremented. 290 */ 291 ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject) 292 { 293 if (referencedObject != newObject) 294 { 295 incIfNotNull (newObject); 296 ReferencedType* const oldObject = referencedObject; 297 referencedObject = newObject; 298 decIfNotNull (oldObject); 299 } 300 301 return *this; 302 } 303 304 #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS 305 /** Takes-over the object from another pointer. */ ReferenceCountedObjectPtr(ReferenceCountedObjectPtr && other)306 ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept 307 : referencedObject (other.referencedObject) 308 { 309 other.referencedObject = nullptr; 310 } 311 312 /** Takes-over the object from another pointer. */ 313 ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) 314 { 315 std::swap (referencedObject, other.referencedObject); 316 return *this; 317 } 318 #endif 319 320 /** Destructor. 321 This will decrement the object's reference-count, which will cause the 322 object to be deleted when the ref-count hits zero. 323 */ ~ReferenceCountedObjectPtr()324 ~ReferenceCountedObjectPtr() 325 { 326 ReferencedType* const oldObject = referencedObject; // need to null the pointer before deleting the object 327 referencedObject = nullptr; // in case this ptr is itself deleted as a side-effect 328 decIfNotNull (oldObject); // of the destructor 329 } 330 331 //============================================================================== 332 /** Returns the object that this pointer references. 333 The pointer returned may be null, of course. 334 */ 335 operator ReferencedType*() const noexcept { return referencedObject; } 336 337 /** Returns the object that this pointer references. 338 The pointer returned may be null, of course. 339 */ get()340 ReferencedType* get() const noexcept { return referencedObject; } 341 342 /** Returns the object that this pointer references. 343 The pointer returned may be null, of course. 344 */ getObject()345 ReferencedType* getObject() const noexcept { return referencedObject; } 346 347 // the -> operator is called on the referenced object 348 ReferencedType* operator->() const noexcept 349 { 350 wassert (referencedObject != nullptr); // null pointer method call! 351 return referencedObject; 352 } 353 354 private: 355 //============================================================================== 356 ReferencedType* referencedObject; 357 incIfNotNull(ReferencedType * o)358 static void incIfNotNull (ReferencedType* o) noexcept 359 { 360 if (o != nullptr) 361 o->incReferenceCount(); 362 } 363 decIfNotNull(ReferencedType * o)364 static void decIfNotNull (ReferencedType* o) noexcept 365 { 366 if (o != nullptr && o->decReferenceCountWithoutDeleting()) 367 delete o; 368 } 369 }; 370 371 372 //============================================================================== 373 /** Compares two ReferenceCountedObjectPtrs. */ 374 template <typename ReferenceCountedObjectClass> 375 bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept 376 { 377 return object1.get() == object2; 378 } 379 380 /** Compares two ReferenceCountedObjectPtrs. */ 381 template <typename ReferenceCountedObjectClass> 382 bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept 383 { 384 return object1.get() == object2.get(); 385 } 386 387 /** Compares two ReferenceCountedObjectPtrs. */ 388 template <typename ReferenceCountedObjectClass> 389 bool operator== (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept 390 { 391 return object1 == object2.get(); 392 } 393 394 /** Compares two ReferenceCountedObjectPtrs. */ 395 template <typename ReferenceCountedObjectClass> 396 bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept 397 { 398 return object1.get() != object2; 399 } 400 401 /** Compares two ReferenceCountedObjectPtrs. */ 402 template <typename ReferenceCountedObjectClass> 403 bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept 404 { 405 return object1.get() != object2.get(); 406 } 407 408 /** Compares two ReferenceCountedObjectPtrs. */ 409 template <typename ReferenceCountedObjectClass> 410 bool operator!= (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept 411 { 412 return object1 != object2.get(); 413 } 414 415 } 416 417 #endif // WATER_REFERENCECOUNTEDOBJECT_H_INCLUDED 418