#ifndef GLTB_REFERENCEDOBJECT_H_ #define GLTB_REFERENCEDOBJECT_H_ #include "GLTB/atomicops.h" namespace gltb { class ReferencedObject; struct ReferenceCounters { ReferenceCounters() : object(nullptr), referenceCount(0), weakReferenceCount(0), spinlock(0) {} ReferencedObject *object; int referenceCount; int weakReferenceCount; unsigned char spinlock; void lock() { while(atomicCAS(&spinlock, 0, 1) != 0); } void unlock() { atomicDec(&spinlock); } }; class ReferencedObject { public: ReferencedObject() { refCounters = new ReferenceCounters(); refCounters->object = this; } virtual ~ReferencedObject() {} void increaseReferenceCount() { int oldRefCount, newRefCount; do { oldRefCount = refCounters->referenceCount; if(oldRefCount < 0) { return; } newRefCount = oldRefCount + 1; } while(atomicCAS(&refCounters->referenceCount, oldRefCount, newRefCount) != oldRefCount); } void decreaseReferenceCount() { int oldRefCount, newRefCount; refCounters->lock(); do { oldRefCount = refCounters->referenceCount; newRefCount = oldRefCount - 1; // if reference count would be 0, set it to -1 instead to immediately block increments if(newRefCount == 0) { newRefCount = -1; } } while(atomicCAS(&refCounters->referenceCount, oldRefCount, newRefCount) != oldRefCount); // test against newRefCount here because referenceCount may have been modified again after the compare_exchange if(newRefCount == -1) { // delete reference counters if no weak references left, either if(refCounters->weakReferenceCount == 0) { delete refCounters; } else { refCounters->object = nullptr; refCounters->unlock(); } delete this; } else { refCounters->unlock(); } } int getReferenceCount() { return refCounters->referenceCount; }; // internal method to get to reference counters; required by WeakPtr class ReferenceCounters *_getReferenceCounters() { return refCounters; } private: ReferenceCounters *refCounters; }; } #endif /*GLTB_REFERENCEDOBJECT_H_*/