Coverage Report

Created: 2025-03-04 07:22

/src/serenity/AK/AtomicRefCounted.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/Assertions.h>
10
#include <AK/Atomic.h>
11
#include <AK/Checked.h>
12
#include <AK/Noncopyable.h>
13
#include <AK/Platform.h>
14
15
namespace AK {
16
17
class AtomicRefCountedBase {
18
    AK_MAKE_NONCOPYABLE(AtomicRefCountedBase);
19
    AK_MAKE_NONMOVABLE(AtomicRefCountedBase);
20
21
public:
22
    using RefCountType = unsigned int;
23
    using AllowOwnPtr = FalseType;
24
25
    void ref() const
26
45
    {
27
45
        auto old_ref_count = m_ref_count.fetch_add(1, AK::MemoryOrder::memory_order_relaxed);
28
45
        VERIFY(old_ref_count > 0);
29
45
        VERIFY(!Checked<RefCountType>::addition_would_overflow(old_ref_count, 1));
30
45
    }
31
32
    [[nodiscard]] bool try_ref() const
33
0
    {
34
0
        RefCountType expected = m_ref_count.load(AK::MemoryOrder::memory_order_relaxed);
35
0
        for (;;) {
36
0
            if (expected == 0)
37
0
                return false;
38
0
            VERIFY(!Checked<RefCountType>::addition_would_overflow(expected, 1));
39
0
            if (m_ref_count.compare_exchange_strong(expected, expected + 1, AK::MemoryOrder::memory_order_acquire))
40
0
                return true;
41
0
        }
42
0
    }
43
44
    [[nodiscard]] RefCountType ref_count() const
45
0
    {
46
0
        return m_ref_count.load(AK::MemoryOrder::memory_order_relaxed);
47
0
    }
48
49
protected:
50
45
    AtomicRefCountedBase() = default;
51
    ~AtomicRefCountedBase()
52
45
    {
53
45
        VERIFY(m_ref_count.load(AK::MemoryOrder::memory_order_relaxed) == 0);
54
45
    }
55
56
    RefCountType deref_base() const
57
90
    {
58
90
        auto old_ref_count = m_ref_count.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel);
59
90
        VERIFY(old_ref_count > 0);
60
90
        return old_ref_count - 1;
61
90
    }
62
63
    mutable Atomic<RefCountType> m_ref_count { 1 };
64
};
65
66
template<typename T>
67
class AtomicRefCounted : public AtomicRefCountedBase {
68
public:
69
    bool unref() const
70
90
    {
71
90
        auto* that = const_cast<T*>(static_cast<T const*>(this));
72
90
        auto new_ref_count = deref_base();
73
90
        if (new_ref_count == 0) {
74
            if constexpr (requires { that->will_be_destroyed(); })
75
                that->will_be_destroyed();
76
45
            delete that;
77
45
            return true;
78
45
        }
79
45
        return false;
80
90
    }
81
};
82
83
}
84
85
#if USING_AK_GLOBALLY
86
using AK::AtomicRefCounted;
87
using AK::AtomicRefCountedBase;
88
#endif