#pragma once #include "fl/ptr.h" #include "fl/referent.h" namespace fl { // Ptr template method implementations template template inline Ptr PtrTraits::New(Args... args) { T *ptr = new T(args...); return Ptr::TakeOwnership(ptr); } template inline Ptr PtrTraits::New() { T *ptr = new T(); return Ptr::TakeOwnership(ptr); } template template inline Ptr Ptr::New(Args... args) { return PtrTraits::New(args...); } // Allow upcasting of Refs. template template inline Ptr::Ptr(const Ptr &refptr) : referent_(refptr.get()) { if (referent_ && isOwned()) { referent_->ref(); } } template inline Ptr::Ptr(const Ptr &other) : referent_(other.referent_) { if (referent_ && isOwned()) { referent_->ref(); } } template inline Ptr::Ptr(Ptr &&other) noexcept : referent_(other.referent_) { other.referent_ = nullptr; } template inline Ptr::~Ptr() { if (referent_ && isOwned()) { referent_->unref(); } } template inline Ptr &Ptr::operator=(const Ptr &other) { if (this != &other) { if (referent_ && isOwned()) { referent_->unref(); } referent_ = other.referent_; if (referent_ && isOwned()) { referent_->ref(); } } return *this; } template inline Ptr &Ptr::operator=(Ptr &&other) noexcept { if (this != &other) { if (referent_ && isOwned()) { referent_->unref(); } referent_ = other.referent_; other.referent_ = nullptr; } return *this; } template inline void Ptr::reset() { if (referent_ && isOwned()) { referent_->unref(); } referent_ = nullptr; } template inline void Ptr::reset(Ptr &refptr) { if (refptr.referent_ != referent_) { if (refptr.referent_ && refptr.isOwned()) { refptr.referent_->ref(); } if (referent_ && isOwned()) { referent_->unref(); } referent_ = refptr.referent_; } } template inline T* Ptr::release() { T *temp = referent_; referent_ = nullptr; return temp; } template inline void Ptr::swap(Ptr &other) noexcept { T *temp = referent_; referent_ = other.referent_; other.referent_ = temp; } template inline Ptr::Ptr(T *referent, bool from_heap) : referent_(referent) { if (referent_ && from_heap) { referent_->ref(); } } // WeakPtr template method implementations template inline WeakPtr::WeakPtr(const Ptr &ptr) : mWeakPtr(nullptr) { if (ptr) { mWeakPtr = ptr->getWeakPtr(); if (!mWeakPtr) { // No weak reference exists yet, create one WeakReferent* weakRef = new WeakReferent(); ptr->setWeakPtr(weakRef); weakRef->setReferent(ptr.get()); mWeakPtr = weakRef; } if (mWeakPtr) { mWeakPtr->ref(); } } } template template inline WeakPtr::WeakPtr(const Ptr &ptr) : mWeakPtr(nullptr) { if (ptr) { mWeakPtr = ptr->getWeakPtr(); if (!mWeakPtr) { // No weak reference exists yet, create one WeakReferent* weakRef = new WeakReferent(); ptr->setWeakPtr(weakRef); weakRef->setReferent(ptr.get()); mWeakPtr = weakRef; } if (mWeakPtr) { mWeakPtr->ref(); } } } template inline WeakPtr::WeakPtr(const WeakPtr &other) : mWeakPtr(other.mWeakPtr) { if (mWeakPtr) { mWeakPtr->ref(); } } template template inline WeakPtr::WeakPtr(const WeakPtr &other) : mWeakPtr(other.mWeakPtr) { if (mWeakPtr) { mWeakPtr->ref(); } } template inline WeakPtr::WeakPtr(WeakPtr &&other) noexcept : mWeakPtr(other.mWeakPtr) { other.mWeakPtr = nullptr; } template inline WeakPtr::~WeakPtr() { reset(); } template inline WeakPtr &WeakPtr::operator=(const WeakPtr &other) { if (this != &other) { if (mWeakPtr) { mWeakPtr->unref(); } mWeakPtr = other.mWeakPtr; if (mWeakPtr) { mWeakPtr->ref(); } } return *this; } template inline Ptr WeakPtr::lock() const { if (!mWeakPtr) { return Ptr(); } T *out = static_cast(mWeakPtr->getReferent()); if (!out) { // The referent has been destroyed return Ptr(); } if (out->ref_count() == 0) { // This is a static object, so the refcount is 0. return Ptr::NoTracking(*out); } // This is a heap object, so we need to ref it. return Ptr::TakeOwnership(static_cast(out)); } template inline bool WeakPtr::expired() const { if (!mWeakPtr) { return true; } if (!mWeakPtr->getReferent()) { return true; } return false; } template inline WeakPtr::operator bool() const { return mWeakPtr && mWeakPtr->getReferent(); } template inline bool WeakPtr::operator!() const { bool ok = *this; return !ok; } template inline bool WeakPtr::operator==(const WeakPtr &other) const { return mWeakPtr == other.mWeakPtr; } template inline bool WeakPtr::operator!=(const WeakPtr &other) const { return !(mWeakPtr != other.mWeakPtr); } template inline bool WeakPtr::operator==(const T *other) const { return lock().get() == other; } template inline bool WeakPtr::operator==(T *other) const { if (!mWeakPtr) { return other == nullptr; } return mWeakPtr->getReferent() == other; } template inline bool WeakPtr::operator==(const Ptr &other) const { if (!mWeakPtr) { return !other; } return mWeakPtr->getReferent() == other.get(); } template inline bool WeakPtr::operator!=(const T *other) const { bool equal = *this == other; return !equal; } template inline void WeakPtr::reset() { if (mWeakPtr) { mWeakPtr->unref(); mWeakPtr = nullptr; } } template inline WeakPtr Ptr::weakRefNoCreate() const { if (!referent_) { return WeakPtr(); } WeakReferent *tmp = get()->getWeakPtr(); if (!tmp) { return WeakPtr(); } T *referent = static_cast(tmp->getReferent()); if (!referent) { return WeakPtr(); } // At this point, we know that our weak referent is valid. // However, the template parameter ensures that either we have // an exact type, or are at least down-castable of it. WeakPtr out; out.mWeakPtr = tmp; if (out.mWeakPtr) { out.mWeakPtr->ref(); } return out; } // Free function templates template inline Ptr NewPtr(Args... args) { return Ptr::New(args...); } template inline Ptr NewPtrNoTracking(T &obj) { return Ptr::NoTracking(obj); } } // namespace fl