Implement weak pointers
authorMikko Rasa <tdb@tdb.fi>
Sat, 6 Feb 2021 11:09:28 +0000 (13:09 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 6 Feb 2021 11:09:28 +0000 (13:09 +0200)
source/core/refptr.h

index 28666ea816380e0547205a1f6d83b14da0e13016..a2160a52c50b1799ce45d87903de94ff2474eaf5 100644 (file)
@@ -11,10 +11,14 @@ struct RefCounts
        };
 
        unsigned count;
+       unsigned weak_count;
 
-       RefCounts(): count(0) { }
+       RefCounts(): count(0), weak_count(0) { }
 };
 
+template<typename T>
+class WeakPtr;
+
 
 /**
 A reference counting smart pointer.  When the last RefPtr for the data gets
@@ -24,6 +28,7 @@ template<typename T>
 class RefPtr
 {
        template<typename U> friend class RefPtr;
+       template<typename U> friend class WeakPtr;
 
 private:
        T *data;
@@ -43,6 +48,9 @@ public:
        template<typename U>
        RefPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
 
+       template<typename U>
+       RefPtr(const WeakPtr<U> &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
+
        ~RefPtr() { decref(); }
 
        RefPtr &operator=(T *);
@@ -53,6 +61,9 @@ public:
        template<typename U>
        RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
 
+       template<typename U>
+       RefPtr &operator=(const WeakPtr<U> &p) { return assign(RefPtr(p)); }
+
 private:
        template<typename U>
        RefPtr &assign(const RefPtr<U> &);
@@ -84,6 +95,48 @@ private:
 };
 
 
+template<typename T>
+class WeakPtr
+{
+       template<typename U> friend class RefPtr;
+       template<typename U> friend class WeakPtr;
+
+private:
+       T *data;
+       RefCounts *counts;
+
+public:
+       WeakPtr(): data(0), counts(0) { }
+private:
+       WeakPtr(T *d, RefCounts *c): data(d), counts(d ? c : 0) { incref(); }
+
+public:
+       WeakPtr(const WeakPtr &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
+
+       template<typename U>
+       WeakPtr(const WeakPtr<U> &p): data(p.get()), counts(data ? p.counts : 0) { incref(); }
+
+       template<typename U>
+       WeakPtr(const RefPtr<U> &p): data(p.data), counts(p.counts) { incref(); }
+
+       WeakPtr &operator=(const WeakPtr &p) { return assign(p); }
+
+       template<typename U>
+       WeakPtr &operator=(const WeakPtr<U> &p) { return assign(p); }
+
+       template<typename U>
+       WeakPtr &operator=(const RefPtr<U> &p) { return assign(WeakPtr(p)); }
+
+private:
+       template<typename U>
+       WeakPtr &assign(const WeakPtr<U> &);
+
+       T *get() const { return (counts && counts->count ? data : 0); }
+       void incref() { if(counts) ++counts->weak_count; }
+       void decref();
+};
+
+
 template<typename T>
 RefPtr<T> &RefPtr<T>::operator=(T *d)
 {
@@ -123,11 +176,38 @@ void RefPtr<T>::decref()
        if(!counts->count)
        {
                delete data;
-               delete counts;
                data = 0;
-               counts = 0;
        }
        else if(counts->count==RefCounts::KEEP)
+               data = 0;
+       else
+               return;
+
+       if(!counts->weak_count)
+       {
+               delete counts;
+               counts = 0;
+       }
+}
+
+
+template<typename T>
+template<typename U>
+WeakPtr<T> &WeakPtr<T>::assign(const WeakPtr<U> &p)
+{
+       decref();
+       data = p.get();
+       counts = (data ? p.counts : 0);
+       incref();
+       return *this;
+}
+
+template<typename T>
+void WeakPtr<T>::decref()
+{
+       if(!counts) return;
+       --counts->weak_count;
+       if(!counts->weak_count && (!counts->count || counts->count==RefCounts::KEEP))
        {
                delete counts;
                data = 0;