summaryrefslogtreecommitdiff
path: root/Kernel/RefPtr.h
blob: 3fa3d30c4977c9cd29bde754fb4834f30826b238 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include "types.h"

#define SANITIZE_REFPTR

template<typename T> class RefPtr;
template<typename T> RefPtr<T> adoptRef(T*);

template<typename T>
class RefPtr {
public:
    RefPtr() { }
    RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(m_ptr); }

    ~RefPtr()
    {
        derefIfNotNull(m_ptr);
#ifdef SANITIZE_REFPTR
        m_ptr = (T*)(0xeeeeeeee);
#endif
    }

    RefPtr(RefPtr&& other)
        : m_ptr(other.leakPtr())
    {
    }

    RefPtr& operator=(RefPtr&& other)
    {
        if (this == &other)
            return *this;
        m_ptr = other.leakPtr();
        return *this;
    }

    template<typename U>
    RefPtr(RefPtr<U>&& other)
        : m_ptr(static_cast<T*>(other.leakPtr()))
    {
    }

    template<typename U>
    RefPtr& operator=(RefPtr<U>&& other)
    {
        if (this == &other)
            return *this;
        m_ptr = static_cast<T*>(other.leakPtr());
        return *this;
    }

    RefPtr(const RefPtr& other)
        : m_ptr(other.m_ptr)
    {
        refIfNotNull(m_ptr);
    }

    RefPtr& operator=(const RefPtr& other)
    {
        if (this == &other)
            return *this;
        m_ptr = other.m_ptr;
        refIfNotNull(m_ptr);
        return *this;
    }

    T* ptr() { return m_ptr; }
    const T* ptr() const { return m_ptr; }
    T* operator->() { return m_ptr; }
    const T* operator->() const { return m_ptr; }
    T& operator*() { return *m_ptr; }
    const T& operator*() const { return *m_ptr; }
    operator bool() const { return m_ptr; }

    T* leakPtr()
    {
        T* ptr = m_ptr;
        m_ptr = nullptr;
        return ptr;
    }

private:
    template<typename U> friend class RefPtr;
    friend RefPtr adoptRef<T>(T*);

    enum AdoptTag { Adopt };
    RefPtr(AdoptTag, T* ptr) : m_ptr(ptr) { }

    inline void refIfNotNull(T* ptr) { if (ptr) ptr->ref(); }
    inline void derefIfNotNull(T* ptr) { if (ptr) ptr->deref(); }

    T* m_ptr { nullptr };
};

template<typename T>
inline RefPtr<T> adoptRef(T* ptr)
{
    ASSERT(ptr->refCount() == 1);
    return RefPtr<T>(RefPtr<T>::Adopt, ptr);
}