#ifndef GLTB_WEAKPTR_H_ #define GLTB_WEAKPTR_H_ #include "GLTB/exception.h" #include "GLTB/mutex.h" #include "GLTB/referencedobject.h" #include "GLTB/refptr.h" namespace gltb { template class WeakPtr { public: WeakPtr() : refCounters(nullptr) {} WeakPtr(RefPtr object) { if(object != 0) { refCounters = object->_getReferenceCounters(); increaseWeakReferenceCount(); } else { refCounters = nullptr; } }; WeakPtr(WeakPtr const &ptr) { if(ptr.refCounters != nullptr) { refCounters = ptr.refCounters; increaseWeakReferenceCount(); } else { refCounters = nullptr; } } template WeakPtr(WeakPtr const &ptr, typename std::enable_if::value, int>::type dummy = 0) { if(ptr.refCounters != nullptr) { refCounters = ptr.refCounters; increaseWeakReferenceCount(); } else { refCounters = nullptr; } } ~WeakPtr() { if(refCounters != nullptr) { decreaseWeakReferenceCount(); } }; WeakPtr &operator =(WeakPtr const &ptr) { if(refCounters != nullptr) { decreaseWeakReferenceCount(); } if(ptr.refCounters != nullptr) { refCounters = ptr.refCounters; increaseWeakReferenceCount(); } else { refCounters = nullptr; } return *this; } RefPtr getRefPtr() { if(refCounters == nullptr) { return nullptr; } refCounters->lock(); // check if ReferencedObject is currently being torn down and don't return a reference in this case if(refCounters->object == nullptr || refCounters->referenceCount == -1) { refCounters->unlock(); return nullptr; } RefPtr refPtr = static_cast(refCounters->object); refCounters->unlock(); return refPtr; } // internal methods to get to reference counters ReferenceCounters *_getReferenceCounters() { return refCounters; } private: ReferenceCounters *refCounters; void increaseWeakReferenceCount() { refCounters->lock(); atomicInc(&refCounters->weakReferenceCount); refCounters->unlock(); } void decreaseWeakReferenceCount() { refCounters->lock(); atomicDec(&refCounters->weakReferenceCount); if(refCounters->weakReferenceCount == 0 && refCounters->referenceCount == -1) { delete refCounters; refCounters = nullptr; } else { refCounters->unlock(); } } }; template bool operator == (WeakPtr reference1, WeakPtr reference2) { return (reference1._getReferenceCounters() == reference2._getReferenceCounters()); } template bool operator != (WeakPtr reference1, WeakPtr reference2) { return (reference1._getReferenceCounters() != reference2._getReferenceCounters()); } template bool operator < (WeakPtr reference1, WeakPtr reference2) { return reference1._getReferenceCounters() < reference2._getReferenceCounters(); } } #endif