/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 |