Blender  V2.93
BLI_heap.c
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 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "MEM_guardedalloc.h"
27 
28 #include "BLI_heap.h"
29 #include "BLI_strict_flags.h"
30 #include "BLI_utildefines.h"
31 
32 /***/
33 
34 struct HeapNode {
35  float value;
37  void *ptr;
38 };
39 
44  struct HeapNode buf[0];
45 };
46 
54 #define HEAP_CHUNK_DEFAULT_NUM \
55  ((uint)((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode)))
56 
57 struct Heap {
61 
62  struct {
63  /* Always keep at least one chunk (never NULL) */
65  /* when NULL, allocate a new chunk */
67  } nodes;
68 };
69 
70 /* -------------------------------------------------------------------- */
74 #define HEAP_PARENT(i) (((i)-1) >> 1)
75 #define HEAP_LEFT(i) (((i) << 1) + 1)
76 #define HEAP_RIGHT(i) (((i) << 1) + 2)
77 #define HEAP_COMPARE(a, b) ((a)->value < (b)->value)
78 
79 #if 0 /* UNUSED */
80 # define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
81 #endif
82 
83 BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
84 {
85 #if 1
86  HeapNode **tree = heap->tree;
87  HeapNode *pi = tree[i], *pj = tree[j];
88  pi->index = j;
89  tree[j] = pi;
90  pj->index = i;
91  tree[i] = pj;
92 #elif 0
93  SWAP(uint, heap->tree[i]->index, heap->tree[j]->index);
94  SWAP(HeapNode *, heap->tree[i], heap->tree[j]);
95 #else
96  HeapNode **tree = heap->tree;
97  union {
98  uint index;
99  HeapNode *node;
100  } tmp;
101  SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index);
102  SWAP_TVAL(tmp.node, tree[i], tree[j]);
103 #endif
104 }
105 
106 static void heap_down(Heap *heap, uint i)
107 {
108  /* size won't change in the loop */
109  HeapNode **const tree = heap->tree;
110  const uint size = heap->size;
111 
112  while (1) {
113  const uint l = HEAP_LEFT(i);
114  const uint r = HEAP_RIGHT(i);
115  uint smallest = i;
116 
117  if (LIKELY(l < size) && HEAP_COMPARE(tree[l], tree[smallest])) {
118  smallest = l;
119  }
120  if (LIKELY(r < size) && HEAP_COMPARE(tree[r], tree[smallest])) {
121  smallest = r;
122  }
123 
124  if (UNLIKELY(smallest == i)) {
125  break;
126  }
127 
128  heap_swap(heap, i, smallest);
129  i = smallest;
130  }
131 }
132 
133 static void heap_up(Heap *heap, uint i)
134 {
135  HeapNode **const tree = heap->tree;
136 
137  while (LIKELY(i > 0)) {
138  const uint p = HEAP_PARENT(i);
139 
140  if (HEAP_COMPARE(tree[p], tree[i])) {
141  break;
142  }
143  heap_swap(heap, p, i);
144  i = p;
145  }
146 }
147 
150 /* -------------------------------------------------------------------- */
154 static struct HeapNode_Chunk *heap_node_alloc_chunk(uint tot_nodes,
155  struct HeapNode_Chunk *chunk_prev)
156 {
157  struct HeapNode_Chunk *chunk = MEM_mallocN(
158  sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__);
159  chunk->prev = chunk_prev;
160  chunk->bufsize = tot_nodes;
161  chunk->size = 0;
162  return chunk;
163 }
164 
165 static struct HeapNode *heap_node_alloc(Heap *heap)
166 {
167  HeapNode *node;
168 
169  if (heap->nodes.free) {
170  node = heap->nodes.free;
171  heap->nodes.free = heap->nodes.free->ptr;
172  }
173  else {
174  struct HeapNode_Chunk *chunk = heap->nodes.chunk;
175  if (UNLIKELY(chunk->size == chunk->bufsize)) {
177  }
178  node = &chunk->buf[chunk->size++];
179  }
180 
181  return node;
182 }
183 
184 static void heap_node_free(Heap *heap, HeapNode *node)
185 {
186  node->ptr = heap->nodes.free;
187  heap->nodes.free = node;
188 }
189 
192 /* -------------------------------------------------------------------- */
201 Heap *BLI_heap_new_ex(uint tot_reserve)
202 {
203  Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
204  /* ensure we have at least one so we can keep doubling it */
205  heap->size = 0;
206  heap->bufsize = MAX2(1u, tot_reserve);
207  heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree");
208 
210  (tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL);
211  heap->nodes.free = NULL;
212 
213  return heap;
214 }
215 
217 {
218  return BLI_heap_new_ex(1);
219 }
220 
221 void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
222 {
223  if (ptrfreefp) {
224  uint i;
225 
226  for (i = 0; i < heap->size; i++) {
227  ptrfreefp(heap->tree[i]->ptr);
228  }
229  }
230 
231  struct HeapNode_Chunk *chunk = heap->nodes.chunk;
232  do {
233  struct HeapNode_Chunk *chunk_prev;
234  chunk_prev = chunk->prev;
235  MEM_freeN(chunk);
236  chunk = chunk_prev;
237  } while (chunk);
238 
239  MEM_freeN(heap->tree);
240  MEM_freeN(heap);
241 }
242 
243 void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
244 {
245  if (ptrfreefp) {
246  uint i;
247 
248  for (i = 0; i < heap->size; i++) {
249  ptrfreefp(heap->tree[i]->ptr);
250  }
251  }
252  heap->size = 0;
253 
254  /* Remove all except the last chunk */
255  while (heap->nodes.chunk->prev) {
256  struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev;
257  MEM_freeN(heap->nodes.chunk);
258  heap->nodes.chunk = chunk_prev;
259  }
260  heap->nodes.chunk->size = 0;
261  heap->nodes.free = NULL;
262 }
263 
268 HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
269 {
270  HeapNode *node;
271 
272  if (UNLIKELY(heap->size >= heap->bufsize)) {
273  heap->bufsize *= 2;
274  heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree));
275  }
276 
277  node = heap_node_alloc(heap);
278 
279  node->ptr = ptr;
280  node->value = value;
281  node->index = heap->size;
282 
283  heap->tree[node->index] = node;
284 
285  heap->size++;
286 
287  heap_up(heap, node->index);
288 
289  return node;
290 }
291 
295 void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
296 {
297  if (*node_p == NULL) {
298  *node_p = BLI_heap_insert(heap, value, ptr);
299  }
300  else {
301  BLI_heap_node_value_update_ptr(heap, *node_p, value, ptr);
302  }
303 }
304 
305 bool BLI_heap_is_empty(const Heap *heap)
306 {
307  return (heap->size == 0);
308 }
309 
310 uint BLI_heap_len(const Heap *heap)
311 {
312  return heap->size;
313 }
314 
320 {
321  return heap->tree[0];
322 }
323 
328 float BLI_heap_top_value(const Heap *heap)
329 {
330  BLI_assert(heap->size != 0);
331 
332  return heap->tree[0]->value;
333 }
334 
338 void *BLI_heap_pop_min(Heap *heap)
339 {
340  BLI_assert(heap->size != 0);
341 
342  void *ptr = heap->tree[0]->ptr;
343 
344  heap_node_free(heap, heap->tree[0]);
345 
346  if (--heap->size) {
347  heap_swap(heap, 0, heap->size);
348  heap_down(heap, 0);
349  }
350 
351  return ptr;
352 }
353 
355 {
356  BLI_assert(heap->size != 0);
357 
358  uint i = node->index;
359 
360  while (i > 0) {
361  uint p = HEAP_PARENT(i);
362  heap_swap(heap, p, i);
363  i = p;
364  }
365 
366  BLI_heap_pop_min(heap);
367 }
368 
374 void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
375 {
376  if (value < node->value) {
377  node->value = value;
378  heap_up(heap, node->index);
379  }
380  else if (value > node->value) {
381  node->value = value;
382  heap_down(heap, node->index);
383  }
384 }
385 
386 void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
387 {
388  node->ptr = ptr; /* only difference */
389  if (value < node->value) {
390  node->value = value;
391  heap_up(heap, node->index);
392  }
393  else if (value > node->value) {
394  node->value = value;
395  heap_down(heap, node->index);
396  }
397 }
398 
399 float BLI_heap_node_value(const HeapNode *heap)
400 {
401  return heap->value;
402 }
403 
404 void *BLI_heap_node_ptr(const HeapNode *heap)
405 {
406  return heap->ptr;
407 }
408 
409 static bool heap_is_minheap(const Heap *heap, uint root)
410 {
411  if (root < heap->size) {
412  if (heap->tree[root]->index != root) {
413  return false;
414  }
415  const uint l = HEAP_LEFT(root);
416  if (l < heap->size) {
417  if (HEAP_COMPARE(heap->tree[l], heap->tree[root]) || !heap_is_minheap(heap, l)) {
418  return false;
419  }
420  }
421  const uint r = HEAP_RIGHT(root);
422  if (r < heap->size) {
423  if (HEAP_COMPARE(heap->tree[r], heap->tree[root]) || !heap_is_minheap(heap, r)) {
424  return false;
425  }
426  }
427  }
428  return true;
429 }
433 bool BLI_heap_is_valid(const Heap *heap)
434 {
435  return heap_is_minheap(heap, 0);
436 }
437 
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
static struct HeapNode * heap_node_alloc(Heap *heap)
Definition: BLI_heap.c:165
bool BLI_heap_is_valid(const Heap *heap)
Definition: BLI_heap.c:433
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
Definition: BLI_heap.c:295
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
Definition: BLI_heap.c:386
BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j)
Definition: BLI_heap.c:83
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
Definition: BLI_heap.c:221
static void heap_down(Heap *heap, uint i)
Definition: BLI_heap.c:106
#define HEAP_PARENT(i)
Definition: BLI_heap.c:74
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
Definition: BLI_heap.c:243
bool BLI_heap_is_empty(const Heap *heap)
Definition: BLI_heap.c:305
void BLI_heap_remove(Heap *heap, HeapNode *node)
Definition: BLI_heap.c:354
static void heap_up(Heap *heap, uint i)
Definition: BLI_heap.c:133
uint BLI_heap_len(const Heap *heap)
Definition: BLI_heap.c:310
static void heap_node_free(Heap *heap, HeapNode *node)
Definition: BLI_heap.c:184
static bool heap_is_minheap(const Heap *heap, uint root)
Definition: BLI_heap.c:409
Heap * BLI_heap_new(void)
Definition: BLI_heap.c:216
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr)
Definition: BLI_heap.c:268
float BLI_heap_node_value(const HeapNode *heap)
Definition: BLI_heap.c:399
#define HEAP_CHUNK_DEFAULT_NUM
Definition: BLI_heap.c:54
void * BLI_heap_pop_min(Heap *heap)
Definition: BLI_heap.c:338
Heap * BLI_heap_new_ex(uint tot_reserve)
Definition: BLI_heap.c:201
#define HEAP_RIGHT(i)
Definition: BLI_heap.c:76
#define HEAP_LEFT(i)
Definition: BLI_heap.c:75
HeapNode * BLI_heap_top(const Heap *heap)
Definition: BLI_heap.c:319
#define HEAP_COMPARE(a, b)
Definition: BLI_heap.c:77
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
Definition: BLI_heap.c:374
float BLI_heap_top_value(const Heap *heap)
Definition: BLI_heap.c:328
void * BLI_heap_node_ptr(const HeapNode *heap)
Definition: BLI_heap.c:404
static struct HeapNode_Chunk * heap_node_alloc_chunk(uint tot_nodes, struct HeapNode_Chunk *chunk_prev)
Definition: BLI_heap.c:154
A min-heap / priority queue ADT.
void(* HeapFreeFP)(void *ptr)
Definition: BLI_heap.h:35
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
#define SWAP_TVAL(tval, a, b)
#define MAX2(a, b)
#define UNLIKELY(x)
#define LIKELY(x)
_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 GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
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
OperationNode * node
void * tree
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
struct HeapNode buf[0]
Definition: BLI_heap.c:44
uint bufsize
Definition: BLI_heap.c:43
struct HeapNode_Chunk * prev
Definition: BLI_heap.c:41
void * ptr
Definition: BLI_heap.c:37
float value
Definition: BLI_heap.c:35
uint index
Definition: BLI_heap.c:36
Definition: BLI_heap.c:57
HeapNode ** tree
Definition: BLI_heap.c:60
struct Heap::@122 nodes
struct HeapNode_Chunk * chunk
Definition: BLI_heap.c:64
uint size
Definition: BLI_heap.c:58
HeapNode * free
Definition: BLI_heap.c:66
uint bufsize
Definition: BLI_heap.c:59
PointerRNA * ptr
Definition: wm_files.c:3157