Coverage Report

Created: 2025-11-16 07:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/AK/BinaryHeap.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/Noncopyable.h>
10
#include <AK/Vector.h>
11
12
namespace AK {
13
14
template<typename Node, typename Comparator, typename IndexSetter, size_t inline_capacity = 0>
15
class IntrusiveBinaryHeap {
16
    AK_MAKE_DEFAULT_COPYABLE(IntrusiveBinaryHeap);
17
    AK_MAKE_DEFAULT_MOVABLE(IntrusiveBinaryHeap);
18
19
public:
20
41.6k
    IntrusiveBinaryHeap() = default;
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::IntrusiveBinaryHeap()
Line
Count
Source
20
41.6k
    IntrusiveBinaryHeap() = default;
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::IntrusiveBinaryHeap()
21
22
    IntrusiveBinaryHeap(Vector<Node, inline_capacity>&& nodes)
23
41.6k
        : m_nodes(move(nodes))
24
41.6k
    {
25
1.29M
        for (ssize_t i = m_nodes.size() / 2; i--;)
26
1.25M
            heapify_down(i);
27
41.6k
    }
28
29
65.3M
    [[nodiscard]] size_t size() const { return m_nodes.size(); }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::size() const
Line
Count
Source
29
65.3M
    [[nodiscard]] size_t size() const { return m_nodes.size(); }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::size() const
30
0
    [[nodiscard]] bool is_empty() const { return m_nodes.is_empty(); }
31
32
    void insert(Node const& node)
33
0
    {
34
0
        m_nodes.append(node);
35
0
        IndexSetter {}(m_nodes.last(), m_nodes.size() - 1);
36
0
        heapify_up(m_nodes.size() - 1);
37
0
    }
38
39
    void insert(Node&& node)
40
2.49M
    {
41
2.49M
        m_nodes.append(move(node));
42
2.49M
        IndexSetter {}(m_nodes.last(), m_nodes.size() - 1);
43
2.49M
        heapify_up(m_nodes.size() - 1);
44
2.49M
    }
45
46
    Node pop(size_t i)
47
4.98M
    {
48
4.98M
        while (i != 0) {
49
0
            swap_indices(i, (i - 1) / 2);
50
0
            i = (i - 1) / 2;
51
0
        }
52
4.98M
        swap_indices(0, m_nodes.size() - 1);
53
4.98M
        Node node = m_nodes.take_last();
54
4.98M
        heapify_down(0);
55
4.98M
        return node;
56
4.98M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::pop(unsigned long)
Line
Count
Source
47
4.98M
    {
48
4.98M
        while (i != 0) {
49
0
            swap_indices(i, (i - 1) / 2);
50
0
            i = (i - 1) / 2;
51
0
        }
52
4.98M
        swap_indices(0, m_nodes.size() - 1);
53
4.98M
        Node node = m_nodes.take_last();
54
4.98M
        heapify_down(0);
55
4.98M
        return node;
56
4.98M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::pop(unsigned long)
57
58
    Node pop_min()
59
4.98M
    {
60
4.98M
        return pop(0);
61
4.98M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::pop_min()
Line
Count
Source
59
4.98M
    {
60
4.98M
        return pop(0);
61
4.98M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::pop_min()
62
63
    Node const& peek_min() const
64
4.98M
    {
65
4.98M
        return m_nodes[0];
66
4.98M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::peek_min() const
Line
Count
Source
64
4.98M
    {
65
4.98M
        return m_nodes[0];
66
4.98M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::peek_min() const
67
68
    void clear()
69
0
    {
70
0
        m_nodes.clear();
71
0
    }
72
73
    ReadonlySpan<Node> nodes_in_arbitrary_order() const
74
0
    {
75
0
        return m_nodes;
76
0
    }
77
78
private:
79
    void swap_indices(size_t i, size_t j)
80
32.2M
    {
81
32.2M
        swap(m_nodes[i], m_nodes[j]);
82
32.2M
        IndexSetter {}(m_nodes[i], i);
83
32.2M
        IndexSetter {}(m_nodes[j], j);
84
32.2M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::swap_indices(unsigned long, unsigned long)
Line
Count
Source
80
32.2M
    {
81
32.2M
        swap(m_nodes[i], m_nodes[j]);
82
32.2M
        IndexSetter {}(m_nodes[i], i);
83
32.2M
        IndexSetter {}(m_nodes[j], j);
84
32.2M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::swap_indices(unsigned long, unsigned long)
85
86
    bool compare_indices(size_t i, size_t j)
87
58.0M
    {
88
58.0M
        return Comparator {}(m_nodes[i], m_nodes[j]);
89
58.0M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::compare_indices(unsigned long, unsigned long)
Line
Count
Source
87
58.0M
    {
88
58.0M
        return Comparator {}(m_nodes[i], m_nodes[j]);
89
58.0M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::compare_indices(unsigned long, unsigned long)
90
91
    void heapify_up(size_t i)
92
2.49M
    {
93
3.26M
        while (i != 0) {
94
3.17M
            auto parent = (i - 1) / 2;
95
3.17M
            if (compare_indices(parent, i))
96
2.40M
                break;
97
770k
            swap_indices(i, parent);
98
770k
            i = parent;
99
770k
        }
100
2.49M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::heapify_up(unsigned long)
Line
Count
Source
92
2.49M
    {
93
3.26M
        while (i != 0) {
94
3.17M
            auto parent = (i - 1) / 2;
95
3.17M
            if (compare_indices(parent, i))
96
2.40M
                break;
97
770k
            swap_indices(i, parent);
98
770k
            i = parent;
99
770k
        }
100
2.49M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::heapify_up(unsigned long)
101
102
    void heapify_down(size_t i)
103
6.24M
    {
104
32.7M
        while (i * 2 + 1 < size()) {
105
27.6M
            size_t min_child = i * 2 + 1;
106
27.6M
            size_t other_child = i * 2 + 2;
107
27.6M
            if (other_child < size() && compare_indices(other_child, min_child))
108
12.2M
                min_child = other_child;
109
27.6M
            if (compare_indices(i, min_child))
110
1.12M
                break;
111
26.4M
            swap_indices(i, min_child);
112
26.4M
            i = min_child;
113
26.4M
        }
114
6.24M
    }
AK::IntrusiveBinaryHeap<AK::BinaryHeap<unsigned short, unsigned short, 288ul>::Node, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeComparator, AK::BinaryHeap<unsigned short, unsigned short, 288ul>::NodeIndexSetter, 0ul>::heapify_down(unsigned long)
Line
Count
Source
103
6.24M
    {
104
32.7M
        while (i * 2 + 1 < size()) {
105
27.6M
            size_t min_child = i * 2 + 1;
106
27.6M
            size_t other_child = i * 2 + 2;
107
27.6M
            if (other_child < size() && compare_indices(other_child, min_child))
108
12.2M
                min_child = other_child;
109
27.6M
            if (compare_indices(i, min_child))
110
1.12M
                break;
111
26.4M
            swap_indices(i, min_child);
112
26.4M
            i = min_child;
113
26.4M
        }
114
6.24M
    }
Unexecuted instantiation: EventLoopImplementationUnix.cpp:AK::IntrusiveBinaryHeap<Core::(anonymous namespace)::EventLoopTimeout*, Core::(anonymous namespace)::TimeoutSet::$_0, Core::(anonymous namespace)::TimeoutSet::$_1, 8ul>::heapify_down(unsigned long)
115
116
    Vector<Node, inline_capacity> m_nodes;
117
};
118
119
template<typename K, typename V, size_t inline_capacity>
120
class BinaryHeap {
121
public:
122
    BinaryHeap() = default;
123
41.6k
    ~BinaryHeap() = default;
124
125
    // This constructor allows for O(n) construction of the heap (instead of O(nlogn) for repeated insertions)
126
    BinaryHeap(K keys[], V values[], size_t size)
127
41.6k
    {
128
41.6k
        Vector<Node, inline_capacity> nodes;
129
41.6k
        nodes.ensure_capacity(size);
130
2.57M
        for (size_t i = 0; i < size; i++)
131
2.53M
            nodes.unchecked_append({ keys[i], values[i] });
132
41.6k
        m_heap = decltype(m_heap) { move(nodes) };
133
41.6k
    }
134
135
5.02M
    [[nodiscard]] size_t size() const { return m_heap.size(); }
136
    [[nodiscard]] bool is_empty() const { return m_heap.is_empty(); }
137
138
    void insert(K key, V value)
139
2.49M
    {
140
2.49M
        m_heap.insert({ key, value });
141
2.49M
    }
142
143
    V pop_min()
144
4.98M
    {
145
4.98M
        return m_heap.pop_min().value;
146
4.98M
    }
147
148
    [[nodiscard]] V const& peek_min() const
149
    {
150
        return m_heap.peek_min().value;
151
    }
152
153
    [[nodiscard]] K const& peek_min_key() const
154
4.98M
    {
155
4.98M
        return m_heap.peek_min().key;
156
4.98M
    }
157
158
    void clear()
159
    {
160
        m_heap.clear();
161
    }
162
163
private:
164
    struct Node {
165
        K key;
166
        V value;
167
    };
168
169
    struct NodeComparator {
170
58.0M
        bool operator()(Node const& a, Node const& b) const { return a.key < b.key; }
171
    };
172
173
    struct NodeIndexSetter {
174
66.9M
        void operator()(Node&, size_t) const { }
175
    };
176
177
    IntrusiveBinaryHeap<Node, NodeComparator, NodeIndexSetter> m_heap;
178
};
179
180
}
181
182
#if USING_AK_GLOBALLY
183
using AK::BinaryHeap;
184
using AK::IntrusiveBinaryHeap;
185
#endif