Blender V4.3
BLI_heap_simple.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
15#include <stdlib.h>
16#include <string.h>
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" /* Keep last. */
24
25#define HEAP_PARENT(i) (((i)-1) >> 1)
26
27/* -------------------------------------------------------------------- */
31typedef struct HeapSimpleNode {
32 float value;
33 void *ptr;
35
41
44/* -------------------------------------------------------------------- */
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
135/* -------------------------------------------------------------------- */
140{
141 HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
142 /* ensure we have at least one so we can keep doubling it */
143 heap->size = 0;
144 heap->bufsize = MAX2(1u, reserve_num);
145 heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapSimpleNode), "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 = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree));
182 }
183
184 heapsimple_up(heap, heap->size++, value, ptr);
185}
186
188{
189 return (heap->size == 0);
190}
191
193{
194 return heap->size;
195}
196
198{
199 BLI_assert(heap->size != 0);
200
201 return heap->tree[0].value;
202}
203
205{
206 BLI_assert(heap->size != 0);
207
208 void *ptr = heap->tree[0].ptr;
209
210 if (--heap->size) {
211 heapsimple_down(heap, 0, &heap->tree[heap->size]);
212 }
213
214 return ptr;
215}
216
#define BLI_assert(a)
Definition BLI_assert.h:50
#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)
uint BLI_heapsimple_len(const HeapSimple *heap)
HeapSimple * BLI_heapsimple_new(void)
struct HeapSimpleNode HeapSimpleNode
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
A min-heap / priority queue ADT.
void(* HeapSimpleFreeFP)(void *ptr)
unsigned int uint
#define MAX2(a, b)
#define UNLIKELY(x)
#define LIKELY(x)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
void init()
KDTree_3d * tree
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
unsigned char uint8_t
Definition stdint.h:78
HeapSimpleNode * tree
PointerRNA * ptr
Definition wm_files.cc:4126