summaryrefslogtreecommitdiff
path: root/AK/Weakable.h
blob: 38999445f16f724812040f3f4e5d5560165218e1 (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
/*
 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Assertions.h>
#include <AK/RefCounted.h>
#include <AK/RefPtr.h>
#include <AK/StdLibExtras.h>

namespace AK {

template<typename T>
class Weakable;
template<typename T>
class WeakPtr;

class WeakLink : public RefCounted<WeakLink> {
    template<typename T>
    friend class Weakable;
    template<typename T>
    friend class WeakPtr;

public:
    template<typename T>
    RefPtr<T> strong_ref() const
    requires(IsBaseOf<RefCountedBase, T>)
    {
        return static_cast<T*>(m_ptr);
    }

    template<typename T>
    T* unsafe_ptr() const
    {
        return static_cast<T*>(m_ptr);
    }

    bool is_null() const { return m_ptr == nullptr; }

    void revoke() { m_ptr = nullptr; }

private:
    template<typename T>
    explicit WeakLink(T& weakable)
        : m_ptr(&weakable)
    {
    }

    mutable void* m_ptr { nullptr };
};

template<typename T>
class Weakable {
private:
    class Link;

public:
    template<typename U = T>
    WeakPtr<U> make_weak_ptr() const
    {
        return MUST(try_make_weak_ptr<U>());
    }

    template<typename U = T>
    ErrorOr<WeakPtr<U>> try_make_weak_ptr() const;

protected:
    Weakable() = default;

    ~Weakable()
    {
        revoke_weak_ptrs();
    }

    void revoke_weak_ptrs()
    {
        if (auto link = move(m_link))
            link->revoke();
    }

private:
    mutable RefPtr<WeakLink> m_link;
};

}

#if USING_AK_GLOBALLY
using AK::Weakable;
#endif