Z-Wave Protocol Controller Reference
priority_queue.hpp
Go to the documentation of this file.
1/******************************************************************************
2 * # License
3 * <b>Copyright 2021 Silicon Laboratories Inc. www.silabs.com</b>
4 ******************************************************************************
5 * The licensor of this software is Silicon Laboratories Inc. Your use of this
6 * software is governed by the terms of Silicon Labs Master Software License
7 * Agreement (MSLA) available at
8 * www.silabs.com/about-us/legal/master-software-license-agreement. This
9 * software is distributed to you in Source Code format and is governed by the
10 * sections of the MSLA applicable to Source Code.
11 *
12 *****************************************************************************/
13#ifndef PRIORITY_QUEUE_HPP
14#define PRIORITY_QUEUE_HPP
15
16// disable out of bound subscript warning. on every index there should be a test
17// for out of bounds
18#pragma GCC diagnostic ignored "-Warray-bounds"
19
20#include <type_traits>
21#include <functional>
22#include <algorithm>
23#include <cassert>
24
25#include "sl_log.h"
26
54template<class T, int Size, class KeyGreater = std::greater<T>>
56{
57 public:
58 using value_type = typename std::decay<T>::type;
60 using const_iterator = const value_type *;
61 using size_type = int;
62
63 constexpr priority_queue() = default;
64
75 bool insert(value_type &&item) noexcept
76 {
77 // since we have a fixed memory size on the buffer. we cannot exceed `Size`
78 // panic if we do.
79 if (size() >= max_size()) {
80 sl_log_error("priority_queue",
81 "Cannot insert a new item since the "
82 "max capacity of %d is reached!",
83 max_size());
84 return false;
85 }
86
87 // if there is only one item in the queue, we dont have to `heapify`
88 // anything.
89 if (size() == 0) {
91 *last = item;
92 return true;
93 }
94
95 // assign item to the next slot. first increase `last` then assign.
96 *(++last) = item;
97
98 // validate the binary heap by moving up the tree. stop when there is a
99 // parent which has not a higher priority.
100 size_type current = size() - 1;
101 size_type parent = parent_index(current);
102
103 KeyGreater greater;
104 while (current != 0 && greater(elements[current], elements[parent])) {
105 std::iter_swap(elements + parent, elements + current);
106 current = parent;
107 parent = parent_index(current);
108 }
109 return true;
110 }
111
123 {
124 assert(!empty());
125
126 // erase returns the iterator following the erased iterator. if that element
127 // is the last in the queue, it will point to `nullptr`. since we know that
128 // the value is still at spot `elements[0]` return it!.
129 if (const auto it = erase(begin()); it == nullptr) {
130 return *elements;
131 }
132
133 // The first element was swapped to the last postition. Even though from
134 // outside of this class, reading `end()` is invalid. we know for sure it
135 // contains the previous element. we can safely create a copy of it here.
136 return *end();
137 }
138
148 {
149 assert(!empty());
150 if (size() > 1) {
151 std::iter_swap(const_cast<T *>(iterator), last--);
152
153 size_type current = iterator - begin();
154 size_type child = biggest_child(current);
155
156 while (child < size()
157 && KeyGreater()(elements[child], elements[current])) {
158 std::iter_swap(elements + current, elements + child);
159 current = child;
160 child = biggest_child(current);
161 }
162 } else {
163 clear();
164 // if there is no item anymore in the queue, begin and end point to
165 // nullptr.
166 return end();
167 }
168
169 // we need to return the next iterator here. because we deleted the current
170 // iterator in the tree, the next node collapsed onto the same spot.
171 // therefore return the same iterator again.
172 return const_cast<priority_queue::iterator>(iterator);
173 }
174
178 constexpr size_type size() const noexcept
179 {
180 return end() - begin();
181 }
182
186 constexpr size_type max_size() const noexcept
187 {
188 return Size;
189 }
190
196 constexpr bool empty() const noexcept
197 {
198 return last == nullptr;
199 }
200
207 constexpr iterator begin() noexcept
208 {
209 return first;
210 }
211
217 constexpr iterator end() noexcept
218 {
219 if (!last) {
220 return last;
221 }
222 return last + 1;
223 }
224
231 constexpr const_iterator begin() const noexcept
232 {
233 return first;
234 }
235
241 constexpr const_iterator end() const noexcept
242 {
243 if (!last) {
244 return last;
245 }
246
247 return last + 1;
248 }
249
255 constexpr void clear() noexcept
256 {
257 first = nullptr;
258 last = nullptr;
259 }
260
261 private:
263 {
264 return (i - 1) / 2;
265 }
266
267 constexpr size_type left_index(size_type i) const
268 {
269 return 2 * i + 1;
270 }
271
272 constexpr size_type right_index(size_type i) const
273 {
274 return 2 * i + 2;
275 }
276
277 inline constexpr size_type biggest_child(size_type current) const
278 {
279 size_type left = left_index(current);
280 size_type right = right_index(current);
281
282 if (right < size() && KeyGreater()(elements[right], elements[left])) {
283 return right;
284 }
285 return left;
286 }
287
288 inline void init_iterators()
289 {
290 first = elements;
291 last = elements;
292 }
293
295 iterator last = nullptr;
296 iterator first = nullptr;
297};
298
299#endif // PRIORITY_QUEUE_HPP
Priority Queue.
Definition: priority_queue.hpp:56
constexpr size_type size() const noexcept
Definition: priority_queue.hpp:178
constexpr size_type right_index(size_type i) const
Definition: priority_queue.hpp:272
value_type pop_front() noexcept
takes the first item in the queue and returns it. The item is deleted from the queue....
Definition: priority_queue.hpp:122
typename std::decay< T >::type value_type
Definition: priority_queue.hpp:58
constexpr size_type parent_index(size_type i) const
Definition: priority_queue.hpp:262
constexpr iterator begin() noexcept
if queue != empty() it returns a pointer to the beginning of the queue. The item with the highest pri...
Definition: priority_queue.hpp:207
constexpr iterator end() noexcept
iterator that points past the last element in the queue.
Definition: priority_queue.hpp:217
constexpr void clear() noexcept
remove all items from the queue.
Definition: priority_queue.hpp:255
void init_iterators()
Definition: priority_queue.hpp:288
value_type * iterator
Definition: priority_queue.hpp:59
constexpr const_iterator end() const noexcept
iterator that points past the last element in the queue.
Definition: priority_queue.hpp:241
constexpr priority_queue()=default
value_type elements[Size]
Definition: priority_queue.hpp:294
iterator last
Definition: priority_queue.hpp:295
constexpr size_type left_index(size_type i) const
Definition: priority_queue.hpp:267
int size_type
Definition: priority_queue.hpp:61
iterator first
Definition: priority_queue.hpp:296
constexpr const_iterator begin() const noexcept
if queue != empty() it returns a pointer to the beginning of the queue. The item with the highest pri...
Definition: priority_queue.hpp:231
constexpr bool empty() const noexcept
returns if the queue is empty. in this case both begin() and end() point to nullptr
Definition: priority_queue.hpp:196
constexpr size_type max_size() const noexcept
Definition: priority_queue.hpp:186
iterator erase(const_iterator iterator)
removes an item from the queue by iterator. Performance: O(log n)
Definition: priority_queue.hpp:147
bool insert(value_type &&item) noexcept
inserts a value into the queue. inserts are ordered by their priority. this function takes O(log n) t...
Definition: priority_queue.hpp:75
const value_type * const_iterator
Definition: priority_queue.hpp:60
constexpr size_type biggest_child(size_type current) const
Definition: priority_queue.hpp:277