Blender  V2.93
BLI_inplace_priority_queue.hh
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #pragma once
18 
19 #include "BLI_array.hh"
20 #include "BLI_dot_export.hh"
21 
22 namespace blender {
23 
33 template<
34  /* Type of the elements in the underlying array. */
35  typename T,
36  /* Binary function that takes two `const T &` inputs and returns true, when the first input has
37  greater priority than the second. */
38  typename FirstHasHigherPriority = std::greater<T>>
40  private:
41  /* Underlying array the priority queue is built upon. This is a span instead of a mutable span,
42  * because this data structure never changes the values itself. */
43  Span<T> data_;
44  /* Maps indices from the heap (binary tree in array format) to indices of the underlying/original
45  * array. */
46  Array<int64_t> heap_to_orig_;
47  /* This is the inversion of the above mapping. */
48  Array<int64_t> orig_to_heap_;
49  /* Number of elements that are currently in the priority queue. */
50  int64_t heap_size_ = 0;
51  /* Function that can be changed to customize how the priority of two elements is compared. */
52  FirstHasHigherPriority first_has_higher_priority_fn_;
53 
54  public:
59  : data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size())
60  {
61  for (const int64_t i : IndexRange(data_.size())) {
62  heap_to_orig_[i] = i;
63  orig_to_heap_[i] = i;
64  }
65 
66  this->rebuild();
67  }
68 
72  void rebuild()
73  {
74  const int final_heap_size = data_.size();
75  if (final_heap_size > 1) {
76  for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) {
77  this->heapify(i, final_heap_size);
78  }
79  }
80  heap_size_ = final_heap_size;
81  }
82 
87  int64_t size() const
88  {
89  return heap_size_;
90  }
91 
96  bool is_empty() const
97  {
98  return heap_size_ == 0;
99  }
100 
106  const T &peek() const
107  {
108  return data_[this->peek_index()];
109  }
110 
116  const T &pop()
117  {
118  return data_[this->pop_index()];
119  }
120 
125  {
126  BLI_assert(!this->is_empty());
127  return heap_to_orig_[0];
128  }
129 
134  {
135  BLI_assert(!this->is_empty());
136  const int64_t top_index_orig = heap_to_orig_[0];
137  heap_size_--;
138  if (heap_size_ > 1) {
139  this->swap_indices(0, heap_size_);
140  this->heapify(0, heap_size_);
141  }
142  return top_index_orig;
143  }
144 
149  void priority_decreased(const int64_t index)
150  {
151  const int64_t heap_index = orig_to_heap_[index];
152  if (heap_index >= heap_size_) {
153  /* This element is not in the queue currently. */
154  return;
155  }
156  this->heapify(heap_index, heap_size_);
157  }
158 
163  void priority_increased(const int64_t index)
164  {
165  int64_t current = orig_to_heap_[index];
166  if (current >= heap_size_) {
167  /* This element is not in the queue currently. */
168  return;
169  }
170  while (true) {
171  if (current == 0) {
172  break;
173  }
174  const int64_t parent = this->get_parent(current);
175  if (this->first_has_higher_priority(parent, current)) {
176  break;
177  }
178  this->swap_indices(current, parent);
179  current = parent;
180  }
181  }
182 
187  void priority_changed(const int64_t index)
188  {
189  this->priority_increased(index);
190  this->priority_decreased(index);
191  }
192 
198  {
199  return heap_to_orig_.as_span().take_front(heap_size_);
200  }
201 
208  {
209  return heap_to_orig_.as_span().drop_front(heap_size_);
210  }
211 
216  {
217  return heap_to_orig_;
218  }
219 
224  std::string to_dot() const
225  {
226  return this->partial_to_dot(heap_size_);
227  }
228 
229  private:
230  bool first_has_higher_priority(const int64_t a, const int64_t b)
231  {
232  const T &value_a = data_[heap_to_orig_[a]];
233  const T &value_b = data_[heap_to_orig_[b]];
234  return first_has_higher_priority_fn_(value_a, value_b);
235  }
236 
237  void swap_indices(const int64_t a, const int64_t b)
238  {
239  std::swap(heap_to_orig_[a], heap_to_orig_[b]);
240  orig_to_heap_[heap_to_orig_[a]] = a;
241  orig_to_heap_[heap_to_orig_[b]] = b;
242  }
243 
244  void heapify(const int64_t parent, const int64_t heap_size)
245  {
246  int64_t max_index = parent;
247  const int left = this->get_left(parent);
248  const int right = this->get_right(parent);
249  if (left < heap_size && this->first_has_higher_priority(left, max_index)) {
250  max_index = left;
251  }
252  if (right < heap_size && this->first_has_higher_priority(right, max_index)) {
253  max_index = right;
254  }
255  if (max_index != parent) {
256  this->swap_indices(parent, max_index);
257  this->heapify(max_index, heap_size);
258  }
259  if (left < heap_size) {
260  BLI_assert(!this->first_has_higher_priority(left, parent));
261  }
262  if (right < heap_size) {
263  BLI_assert(!this->first_has_higher_priority(right, parent));
264  }
265  }
266 
267  int64_t get_parent(const int64_t child) const
268  {
269  BLI_assert(child > 0);
270  return (child - 1) / 2;
271  }
272 
273  int64_t get_left(const int64_t parent) const
274  {
275  return parent * 2 + 1;
276  }
277 
278  int64_t get_right(const int64_t parent) const
279  {
280  return parent * 2 + 2;
281  }
282 
283  std::string partial_to_dot(const int size) const
284  {
285  dot::DirectedGraph digraph;
286  Array<dot::Node *> dot_nodes(size);
287  for (const int i : IndexRange(size)) {
288  std::stringstream ss;
289  ss << data_[heap_to_orig_[i]];
290  const std::string name = ss.str();
291  dot::Node &node = digraph.new_node(name);
292  node.set_shape(dot::Attr_shape::Rectangle);
293  node.attributes.set("ordering", "out");
294  dot_nodes[i] = &node;
295  if (i > 0) {
296  const int64_t parent = this->get_parent(i);
297  digraph.new_edge(*dot_nodes[parent], node);
298  }
299  }
300  return digraph.to_dot_string();
301  }
302 };
303 
304 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:58
void swap(T &a, T &b)
Definition: Common.h:33
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble right
Span< T > as_span() const
Definition: BLI_array.hh:245
void priority_decreased(const int64_t index)
void priority_increased(const int64_t index)
void priority_changed(const int64_t index)
constexpr Span drop_front(int64_t n) const
Definition: BLI_span.hh:173
constexpr Span take_front(int64_t n) const
Definition: BLI_span.hh:195
DirectedEdge & new_edge(NodePort from, NodePort to)
Definition: dot_export.cc:51
std::string to_dot_string() const
Definition: dot_export.cc:135
Node & new_node(StringRef label)
Definition: dot_export.cc:26
OperationNode * node
T * data_
static int left
#define T
static unsigned a[3]
Definition: RandGen.cpp:92
__int64 int64_t
Definition: stdint.h:92