Blender V5.0
BLI_heap_simple.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
14
15#include <algorithm>
16#include <cstdlib>
17
18#include "MEM_guardedalloc.h"
19
20#include "BLI_heap_simple.h"
21#include "BLI_utildefines.h"
22
23#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
24
25#define HEAP_PARENT(i) (((i) - 1) >> 1)
26
27/* -------------------------------------------------------------------- */
30
32 float value;
33 void *ptr;
34};
35
41
43
44/* -------------------------------------------------------------------- */
47
48static void heapsimple_down(HeapSimple *heap, uint start_i, const HeapSimpleNode *init)
49{
50#if 1
51 /* The compiler isn't smart enough to realize that all computations
52 * using index here can be modified to work with byte offset. */
53 uint8_t *const tree_buf = (uint8_t *)heap->tree;
54
55# define OFFSET(i) (i * uint(sizeof(HeapSimpleNode)))
56# define NODE(offset) (*(HeapSimpleNode *)(tree_buf + (offset)))
57#else
58 HeapSimpleNode *const tree = heap->tree;
59
60# define OFFSET(i) (i)
61# define NODE(i) tree[i]
62#endif
63
64#define HEAP_LEFT_OFFSET(i) (((i) << 1) + OFFSET(1))
65
66 const uint size = OFFSET(heap->size);
67
68 /* Pull the active node values into locals. This allows spilling
69 * the data from registers instead of literally swapping nodes. */
70 float active_val = init->value;
71 void *active_ptr = init->ptr;
72
73 /* Prepare the first iteration and spill value. */
74 uint i = OFFSET(start_i);
75
76 NODE(i).value = active_val;
77
78 for (;;) {
79 const uint l = HEAP_LEFT_OFFSET(i);
80 const uint r = l + OFFSET(1); /* right */
81
82 /* Find the child with the smallest value. */
83 uint smallest = i;
84
85 if (LIKELY(l < size) && NODE(l).value < active_val) {
86 smallest = l;
87 }
88 if (LIKELY(r < size) && NODE(r).value < NODE(smallest).value) {
89 smallest = r;
90 }
91
92 if (UNLIKELY(smallest == i)) {
93 break;
94 }
95
96 /* Move the smallest child into the current node.
97 * Skip padding: for some reason that makes it faster here. */
98 NODE(i).value = NODE(smallest).value;
99 NODE(i).ptr = NODE(smallest).ptr;
100
101 /* Proceed to next iteration and spill value. */
102 i = smallest;
103 NODE(i).value = active_val;
104 }
105
106 /* Spill the pointer into the final position of the node. */
107 NODE(i).ptr = active_ptr;
108
109#undef NODE
110#undef OFFSET
111#undef HEAP_LEFT_OFFSET
112}
113
114static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *active_ptr)
115{
116 HeapSimpleNode *const tree = heap->tree;
117
118 while (LIKELY(i > 0)) {
119 const uint p = HEAP_PARENT(i);
120
121 if (active_val >= tree[p].value) {
122 break;
123 }
124
125 tree[i] = tree[p];
126 i = p;
127 }
128
129 tree[i].value = active_val;
130 tree[i].ptr = active_ptr;
131}
132
134
135/* -------------------------------------------------------------------- */
138
140{
141 HeapSimple *heap = MEM_callocN<HeapSimple>(__func__);
142 /* ensure we have at least one so we can keep doubling it */
143 heap->size = 0;
144 heap->bufsize = std::max(1u, reserve_num);
145 heap->tree = MEM_calloc_arrayN<HeapSimpleNode>(heap->bufsize, "BLIHeapSimpleTree");
146 return heap;
147}
148
153
155{
156 if (ptrfreefp) {
157 for (uint i = 0; i < heap->size; i++) {
158 ptrfreefp(heap->tree[i].ptr);
159 }
160 }
161
162 MEM_freeN(heap->tree);
163 MEM_freeN(heap);
164}
165
167{
168 if (ptrfreefp) {
169 for (uint i = 0; i < heap->size; i++) {
170 ptrfreefp(heap->tree[i].ptr);
171 }
172 }
173
174 heap->size = 0;
175}
176
177void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
178{
179 if (UNLIKELY(heap->size >= heap->bufsize)) {
180 heap->bufsize *= 2;
181 heap->tree = static_cast<HeapSimpleNode *>(
182 MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree)));
183 }
184
185 heapsimple_up(heap, heap->size++, value, ptr);
186}
187
189{
190 return (heap->size == 0);
191}
192
194{
195 return heap->size;
196}
197
199{
200 BLI_assert(heap->size != 0);
201
202 return heap->tree[0].value;
203}
204
206{
207 BLI_assert(heap->size != 0);
208
209 void *ptr = heap->tree[0].ptr;
210
211 if (--heap->size) {
212 heapsimple_down(heap, 0, &heap->tree[heap->size]);
213 }
214
215 return ptr;
216}
217
#define BLI_assert(a)
Definition BLI_assert.h:46
#define HEAP_LEFT_OFFSET(i)
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *active_ptr)
#define OFFSET(i)
#define NODE(offset)
bool BLI_heapsimple_is_empty(const HeapSimple *heap)
#define HEAP_PARENT(i)
HeapSimple * BLI_heapsimple_new_ex(uint reserve_num)
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
float BLI_heapsimple_top_value(const HeapSimple *heap)
void * BLI_heapsimple_pop_min(HeapSimple *heap)
static void heapsimple_down(HeapSimple *heap, uint start_i, const HeapSimpleNode *init)
HeapSimple * BLI_heapsimple_new()
uint BLI_heapsimple_len(const HeapSimple *heap)
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
A min-heap / priority queue ADT.
void(* HeapSimpleFreeFP)(void *ptr)
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_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
static void init(bNodeTree *, bNode *node)
HeapSimpleNode * tree
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238