/* * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef _WEAK_REFERENCEABLE_H #define _WEAK_REFERENCEABLE_H #include namespace BPrivate { template class WeakReferenceable; template class WeakPointer : public Referenceable { public: Type* Get(); bool Put(); int32 UseCount() const; private: friend class WeakReferenceable; WeakPointer(Type* object); ~WeakPointer(); private: void _GetUnchecked(); private: vint32 fUseCount; Type* fObject; }; template class WeakReferenceable { public: WeakReferenceable(Type* object); ~WeakReferenceable(); void AddReference() { fPointer->_GetUnchecked(); } bool RemoveReference() { return fPointer->Put(); } int32 CountReferences() const { return fPointer->UseCount(); } WeakPointer* GetWeakPointer(); protected: WeakPointer* fPointer; }; template class WeakReference { public: WeakReference() : fPointer(NULL), fObject(NULL) { } WeakReference(Type* object) : fPointer(NULL), fObject(NULL) { SetTo(object); } WeakReference(WeakPointer& other) : fPointer(NULL), fObject(NULL) { SetTo(&other); } WeakReference(WeakPointer* other) : fPointer(NULL), fObject(NULL) { SetTo(other); } WeakReference(const WeakReference& other) : fPointer(NULL), fObject(NULL) { SetTo(other.fPointer); } ~WeakReference() { Unset(); } void SetTo(Type* object) { Unset(); if (object != NULL) { fPointer = object->GetWeakPointer(); fObject = fPointer->Get(); } } void SetTo(WeakPointer* pointer) { Unset(); if (pointer != NULL) { fPointer = pointer; fPointer->AddReference(); fObject = pointer->Get(); } } void Unset() { if (fPointer != NULL) { if (fObject != NULL) { fPointer->Put(); fObject = NULL; } fPointer->RemoveReference(); fPointer = NULL; } } Type* Get() const { return fObject; } Type* Detach() { Type* object = fObject; Unset(); return object; } Type& operator*() const { return *fObject; } operator Type*() const { return fObject; } Type* operator->() const { return fObject; } WeakReference& operator=(const WeakReference& other) { if (this == &other) return *this; SetTo(other.fPointer); return *this; } WeakReference& operator=(const Type& other) { SetTo(&other); return *this; } WeakReference& operator=(WeakPointer& other) { SetTo(&other); return *this; } WeakReference& operator=(WeakPointer* other) { SetTo(other); return *this; } bool operator==(const WeakReference& other) const { return fPointer == other.fPointer; } bool operator!=(const WeakReference& other) const { return fPointer != other.fPointer; } private: WeakPointer* fPointer; Type* fObject; }; // #pragma mark - template inline Type* WeakPointer::Get() { int32 count = -11; do { count = atomic_get(&fUseCount); if (count == 0) return NULL; } while (atomic_test_and_set(&fUseCount, count + 1, count) != count); return fObject; } template inline bool WeakPointer::Put() { if (atomic_add(&fUseCount, -1) == 1) { delete fObject; return true; } return false; } template inline int32 WeakPointer::UseCount() const { return fUseCount; } template inline WeakPointer::WeakPointer(Type* object) : fUseCount(1), fObject(object) { } template inline WeakPointer::~WeakPointer() { } template inline void WeakPointer::_GetUnchecked() { atomic_add(&fUseCount, 1); } // #pragma - template inline WeakReferenceable::WeakReferenceable(Type* object) : fPointer(new WeakPointer(object)) { } template inline WeakReferenceable::~WeakReferenceable() { fPointer->RemoveReference(); } template inline WeakPointer* WeakReferenceable::GetWeakPointer() { fPointer->AddReference(); return fPointer; } } // namespace BPrivate using BPrivate::WeakReferenceable; using BPrivate::WeakPointer; using BPrivate::WeakReference; #endif // _WEAK_REFERENCEABLE_H