Blender V5.0
BLI_heap.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <algorithm>
12#include <cstdlib>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_heap.h"
17#include "BLI_utildefines.h"
18
19#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
20
21/***/
22
23struct HeapNode {
24 float value;
26 void *ptr;
27};
28
35
43#define HEAP_CHUNK_DEFAULT_NUM \
44 uint(MEM_SIZE_OPTIMAL((1 << 16) - sizeof(HeapNode_Chunk)) / sizeof(HeapNode))
45
46struct Heap {
50
51 struct {
52 /* Always keep at least one chunk (never nullptr) */
54 /* when nullptr, allocate a new chunk */
57};
58
59/* -------------------------------------------------------------------- */
62
63#define HEAP_PARENT(i) (((i) - 1) >> 1)
64#define HEAP_LEFT(i) (((i) << 1) + 1)
65#define HEAP_RIGHT(i) (((i) << 1) + 2)
66#define HEAP_COMPARE(a, b) ((a)->value < (b)->value)
67
68#if 0 /* UNUSED */
69# define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
70#endif
71
72BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
73{
74 HeapNode **tree = heap->tree;
75 HeapNode *pi = tree[i], *pj = tree[j];
76 pi->index = j;
77 tree[j] = pi;
78 pj->index = i;
79 tree[i] = pj;
80}
81
82static void heap_down(Heap *heap, uint i)
83{
84 /* size won't change in the loop */
85 HeapNode **const tree = heap->tree;
86 const uint size = heap->size;
87
88 while (true) {
89 const uint l = HEAP_LEFT(i);
90 const uint r = HEAP_RIGHT(i);
91 uint smallest = i;
92
93 if (LIKELY(l < size) && HEAP_COMPARE(tree[l], tree[smallest])) {
94 smallest = l;
95 }
96 if (LIKELY(r < size) && HEAP_COMPARE(tree[r], tree[smallest])) {
97 smallest = r;
98 }
99
100 if (UNLIKELY(smallest == i)) {
101 break;
102 }
103
104 heap_swap(heap, i, smallest);
105 i = smallest;
106 }
107}
108
109static void heap_up(Heap *heap, uint i)
110{
111 HeapNode **const tree = heap->tree;
112
113 while (LIKELY(i > 0)) {
114 const uint p = HEAP_PARENT(i);
115
116 if (HEAP_COMPARE(tree[p], tree[i])) {
117 break;
118 }
119 heap_swap(heap, p, i);
120 i = p;
121 }
122}
123
125
126/* -------------------------------------------------------------------- */
129
131{
132 HeapNode_Chunk *chunk = static_cast<HeapNode_Chunk *>(
133 MEM_mallocN(sizeof(HeapNode_Chunk) + (sizeof(HeapNode) * nodes_num), __func__));
134 chunk->prev = chunk_prev;
135 chunk->bufsize = nodes_num;
136 chunk->size = 0;
137 return chunk;
138}
139
141{
142 HeapNode *node;
143
144 if (heap->nodes.free) {
145 node = heap->nodes.free;
146 heap->nodes.free = static_cast<HeapNode *>(heap->nodes.free->ptr);
147 }
148 else {
149 HeapNode_Chunk *chunk = heap->nodes.chunk;
150 if (UNLIKELY(chunk->size == chunk->bufsize)) {
152 }
153 node = &chunk->buf[chunk->size++];
154 }
155
156 return node;
157}
158
159static void heap_node_free(Heap *heap, HeapNode *node)
160{
161 node->ptr = heap->nodes.free;
162 heap->nodes.free = node;
163}
164
166
167/* -------------------------------------------------------------------- */
170
172{
173 Heap *heap = MEM_callocN<Heap>(__func__);
174 /* ensure we have at least one so we can keep doubling it */
175 heap->size = 0;
176 heap->bufsize = std::max(1u, reserve_num);
177 heap->tree = MEM_calloc_arrayN<HeapNode *>(heap->bufsize, "BLIHeapTree");
178
180 (reserve_num > 1) ? reserve_num : HEAP_CHUNK_DEFAULT_NUM, nullptr);
181 heap->nodes.free = nullptr;
182
183 return heap;
184}
185
187{
188 return BLI_heap_new_ex(1);
189}
190
191void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
192{
193 if (ptrfreefp) {
194 uint i;
195
196 for (i = 0; i < heap->size; i++) {
197 ptrfreefp(heap->tree[i]->ptr);
198 }
199 }
200
201 HeapNode_Chunk *chunk = heap->nodes.chunk;
202 do {
203 HeapNode_Chunk *chunk_prev;
204 chunk_prev = chunk->prev;
205 MEM_freeN(chunk);
206 chunk = chunk_prev;
207 } while (chunk);
208
209 MEM_freeN(heap->tree);
210 MEM_freeN(heap);
211}
212
213void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
214{
215 if (ptrfreefp) {
216 uint i;
217
218 for (i = 0; i < heap->size; i++) {
219 ptrfreefp(heap->tree[i]->ptr);
220 }
221 }
222 heap->size = 0;
223
224 /* Remove all except the last chunk */
225 while (heap->nodes.chunk->prev) {
226 HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev;
227 MEM_freeN(heap->nodes.chunk);
228 heap->nodes.chunk = chunk_prev;
229 }
230 heap->nodes.chunk->size = 0;
231 heap->nodes.free = nullptr;
232}
233
234HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
235{
236 HeapNode *node;
237
238 if (UNLIKELY(heap->size >= heap->bufsize)) {
239 heap->bufsize *= 2;
240 heap->tree = static_cast<HeapNode **>(
241 MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree)));
242 }
243
244 node = heap_node_alloc(heap);
245
246 node->ptr = ptr;
247 node->value = value;
248 node->index = heap->size;
249
250 heap->tree[node->index] = node;
251
252 heap->size++;
253
254 heap_up(heap, node->index);
255
256 return node;
257}
258
259void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
260{
261 if (*node_p == nullptr) {
262 *node_p = BLI_heap_insert(heap, value, ptr);
263 }
264 else {
265 BLI_heap_node_value_update_ptr(heap, *node_p, value, ptr);
266 }
267}
268
269bool BLI_heap_is_empty(const Heap *heap)
270{
271 return (heap->size == 0);
272}
273
275{
276 return heap->size;
277}
278
280{
281 return heap->tree[0];
282}
283
284float BLI_heap_top_value(const Heap *heap)
285{
286 BLI_assert(heap->size != 0);
287
288 return heap->tree[0]->value;
289}
290
292{
293 BLI_assert(heap->size != 0);
294
295 void *ptr = heap->tree[0]->ptr;
296
297 heap_node_free(heap, heap->tree[0]);
298
299 if (--heap->size) {
300 heap_swap(heap, 0, heap->size);
301 heap_down(heap, 0);
302 }
303
304 return ptr;
305}
306
307void BLI_heap_remove(Heap *heap, HeapNode *node)
308{
309 BLI_assert(heap->size != 0);
310
311 uint i = node->index;
312
313 while (i > 0) {
314 uint p = HEAP_PARENT(i);
315 heap_swap(heap, p, i);
316 i = p;
317 }
318
319 BLI_heap_pop_min(heap);
320}
321
322void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
323{
324 if (value < node->value) {
325 node->value = value;
326 heap_up(heap, node->index);
327 }
328 else if (value > node->value) {
329 node->value = value;
330 heap_down(heap, node->index);
331 }
332}
333
334void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
335{
336 node->ptr = ptr; /* only difference */
337 if (value < node->value) {
338 node->value = value;
339 heap_up(heap, node->index);
340 }
341 else if (value > node->value) {
342 node->value = value;
343 heap_down(heap, node->index);
344 }
345}
346
348{
349 return heap->value;
350}
351
352void *BLI_heap_node_ptr(const HeapNode *heap)
353{
354 return heap->ptr;
355}
356
357static bool heap_is_minheap(const Heap *heap, uint root)
358{
359 if (root < heap->size) {
360 if (heap->tree[root]->index != root) {
361 return false;
362 }
363 const uint l = HEAP_LEFT(root);
364 if (l < heap->size) {
365 if (HEAP_COMPARE(heap->tree[l], heap->tree[root]) || !heap_is_minheap(heap, l)) {
366 return false;
367 }
368 }
369 const uint r = HEAP_RIGHT(root);
370 if (r < heap->size) {
371 if (HEAP_COMPARE(heap->tree[r], heap->tree[root]) || !heap_is_minheap(heap, r)) {
372 return false;
373 }
374 }
375 }
376 return true;
377}
378bool BLI_heap_is_valid(const Heap *heap)
379{
380 return heap_is_minheap(heap, 0);
381}
382
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
void * BLI_heap_node_ptr(const HeapNode *heap)
Definition BLI_heap.cc:352
bool BLI_heap_is_valid(const Heap *heap)
Definition BLI_heap.cc:378
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
Definition BLI_heap.cc:259
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
Definition BLI_heap.cc:334
BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
Definition BLI_heap.cc:72
void * BLI_heap_pop_min(Heap *heap)
Definition BLI_heap.cc:291
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
Definition BLI_heap.cc:191
static void heap_down(Heap *heap, uint i)
Definition BLI_heap.cc:82
#define HEAP_PARENT(i)
Definition BLI_heap.cc:63
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
Definition BLI_heap.cc:213
bool BLI_heap_is_empty(const Heap *heap)
Definition BLI_heap.cc:269
void BLI_heap_remove(Heap *heap, HeapNode *node)
Definition BLI_heap.cc:307
Heap * BLI_heap_new()
Definition BLI_heap.cc:186
static void heap_up(Heap *heap, uint i)
Definition BLI_heap.cc:109
uint BLI_heap_len(const Heap *heap)
Definition BLI_heap.cc:274
HeapNode * BLI_heap_top(const Heap *heap)
Definition BLI_heap.cc:279
static void heap_node_free(Heap *heap, HeapNode *node)
Definition BLI_heap.cc:159
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr)
Definition BLI_heap.cc:234
static bool heap_is_minheap(const Heap *heap, uint root)
Definition BLI_heap.cc:357
Heap * BLI_heap_new_ex(uint reserve_num)
Definition BLI_heap.cc:171
float BLI_heap_node_value(const HeapNode *heap)
Definition BLI_heap.cc:347
static HeapNode * heap_node_alloc(Heap *heap)
Definition BLI_heap.cc:140
#define HEAP_CHUNK_DEFAULT_NUM
Definition BLI_heap.cc:43
#define HEAP_RIGHT(i)
Definition BLI_heap.cc:65
static HeapNode_Chunk * heap_node_alloc_chunk(uint nodes_num, HeapNode_Chunk *chunk_prev)
Definition BLI_heap.cc:130
#define HEAP_LEFT(i)
Definition BLI_heap.cc:64
#define HEAP_COMPARE(a, b)
Definition BLI_heap.cc:66
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
Definition BLI_heap.cc:322
float BLI_heap_top_value(const Heap *heap)
Definition BLI_heap.cc:284
A min-heap / priority queue ADT.
void(* HeapFreeFP)(void *ptr)
Definition BLI_heap.h:22
unsigned int uint
#define UNLIKELY(x)
#define LIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
KDTree_3d * tree
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
HeapNode buf[0]
Definition BLI_heap.cc:33
HeapNode_Chunk * prev
Definition BLI_heap.cc:30
void * ptr
Definition BLI_heap.cc:26
float value
Definition BLI_heap.cc:24
uint index
Definition BLI_heap.cc:25
HeapNode_Chunk * chunk
Definition BLI_heap.cc:53
HeapNode ** tree
Definition BLI_heap.cc:49
uint size
Definition BLI_heap.cc:47
HeapNode * free
Definition BLI_heap.cc:55
uint bufsize
Definition BLI_heap.cc:48
struct Heap::@127025266276276101366113133025016245344057331056 nodes
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238