| 
									
										
										
										
											2011-02-23 10:52:22 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							| 
									
										
										
										
											2008-04-16 22:40:48 +00:00
										 |  |  |  * of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-18 08:08:12 +11:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bli | 
					
						
							| 
									
										
										
										
											2013-07-02 10:14:59 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2017-10-29 16:07:07 +11:00
										 |  |  |  * A min-heap / priority queue ADT. | 
					
						
							| 
									
										
										
										
											2011-02-27 20:37:56 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-19 19:59:49 +00:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							| 
									
										
										
										
											2013-03-09 05:35:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | #include "BLI_heap.h"
 | 
					
						
							| 
									
										
										
										
											2013-09-01 00:46:04 +00:00
										 |  |  | #include "BLI_strict_flags.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2013-05-08 12:55:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | /***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct HeapNode { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |   float value; | 
					
						
							|  |  |  |   uint index; | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |   void *ptr; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  | struct HeapNode_Chunk { | 
					
						
							|  |  |  |   struct HeapNode_Chunk *prev; | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |   uint size; | 
					
						
							|  |  |  |   uint bufsize; | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   struct HeapNode buf[0]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Number of nodes to include per #HeapNode_Chunk when no reserved size is passed, | 
					
						
							|  |  |  |  * or we allocate past the reserved number. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note Optimize number for 64kb allocs. | 
					
						
							| 
									
										
										
										
											2016-08-01 17:58:45 +02:00
										 |  |  |  * \note keep type in sync with tot_nodes in heap_node_alloc_chunk. | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |  */ | 
					
						
							|  |  |  | #define HEAP_CHUNK_DEFAULT_NUM \
 | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |   ((uint)((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode))) | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | struct Heap { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |   uint size; | 
					
						
							|  |  |  |   uint bufsize; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   HeapNode **tree; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   struct { | 
					
						
							|  |  |  |     /* Always keep at least one chunk (never NULL) */ | 
					
						
							|  |  |  |     struct HeapNode_Chunk *chunk; | 
					
						
							|  |  |  |     /* when NULL, allocate a new chunk */ | 
					
						
							|  |  |  |     HeapNode *free; | 
					
						
							|  |  |  |   } nodes; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-27 21:32:09 +11:00
										 |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  | /** \name Internal Functions
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-02 13:54:06 +10:00
										 |  |  | #define HEAP_PARENT(i) (((i)-1) >> 1)
 | 
					
						
							|  |  |  | #define HEAP_LEFT(i) (((i) << 1) + 1)
 | 
					
						
							|  |  |  | #define HEAP_RIGHT(i) (((i) << 1) + 2)
 | 
					
						
							|  |  |  | #define HEAP_COMPARE(a, b) ((a)->value < (b)->value)
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | #if 0 /* UNUSED */
 | 
					
						
							| 
									
										
										
										
											2015-08-02 13:54:06 +10:00
										 |  |  | #  define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  | BLI_INLINE void heap_swap(Heap *heap, const uint i, const uint j) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  | #if 1
 | 
					
						
							|  |  |  |   HeapNode **tree = heap->tree; | 
					
						
							|  |  |  |   HeapNode *pi = tree[i], *pj = tree[j]; | 
					
						
							|  |  |  |   pi->index = j; | 
					
						
							|  |  |  |   tree[j] = pi; | 
					
						
							|  |  |  |   pj->index = i; | 
					
						
							|  |  |  |   tree[i] = pj; | 
					
						
							|  |  |  | #elif 0
 | 
					
						
							| 
									
										
										
										
											2018-10-19 09:07:40 +11:00
										 |  |  |   SWAP(uint, heap->tree[i]->index, heap->tree[j]->index); | 
					
						
							|  |  |  |   SWAP(HeapNode *, heap->tree[i], heap->tree[j]); | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |   HeapNode **tree = heap->tree; | 
					
						
							|  |  |  |   union { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     uint index; | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |     HeapNode *node; | 
					
						
							|  |  |  |   } tmp; | 
					
						
							|  |  |  |   SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index); | 
					
						
							|  |  |  |   SWAP_TVAL(tmp.node, tree[i], tree[j]); | 
					
						
							| 
									
										
										
										
											2018-10-19 09:07:40 +11:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  | static void heap_down(Heap *heap, uint i) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-22 13:00:02 +00:00
										 |  |  |   /* size won't change in the loop */ | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |   HeapNode **const tree = heap->tree; | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |   const uint size = heap->size; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   while (1) { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     const uint l = HEAP_LEFT(i); | 
					
						
							|  |  |  |     const uint r = HEAP_RIGHT(i); | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |     uint smallest = i; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |     if (LIKELY(l < size) && HEAP_COMPARE(tree[l], tree[smallest])) { | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |       smallest = l; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |     if (LIKELY(r < size) && HEAP_COMPARE(tree[r], tree[smallest])) { | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |       smallest = r; | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |     if (UNLIKELY(smallest == i)) { | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |     heap_swap(heap, i, smallest); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |     i = smallest; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  | static void heap_up(Heap *heap, uint i) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |   HeapNode **const tree = heap->tree; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (LIKELY(i > 0)) { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     const uint p = HEAP_PARENT(i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |     if (HEAP_COMPARE(tree[p], tree[i])) { | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |     heap_swap(heap, p, i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |     i = p; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  | /** \} */ | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-27 21:32:09 +11:00
										 |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  | /** \name Internal Memory Management
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct HeapNode_Chunk *heap_node_alloc_chunk(uint tot_nodes, | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |                                                     struct HeapNode_Chunk *chunk_prev) | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  | { | 
					
						
							|  |  |  |   struct HeapNode_Chunk *chunk = MEM_mallocN( | 
					
						
							|  |  |  |       sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__); | 
					
						
							|  |  |  |   chunk->prev = chunk_prev; | 
					
						
							|  |  |  |   chunk->bufsize = tot_nodes; | 
					
						
							|  |  |  |   chunk->size = 0; | 
					
						
							|  |  |  |   return chunk; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct HeapNode *heap_node_alloc(Heap *heap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   HeapNode *node; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   if (heap->nodes.free) { | 
					
						
							|  |  |  |     node = heap->nodes.free; | 
					
						
							|  |  |  |     heap->nodes.free = heap->nodes.free->ptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     struct HeapNode_Chunk *chunk = heap->nodes.chunk; | 
					
						
							|  |  |  |     if (UNLIKELY(chunk->size == chunk->bufsize)) { | 
					
						
							| 
									
										
										
										
											2016-07-21 00:33:37 +10:00
										 |  |  |       chunk = heap->nodes.chunk = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk); | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |     } | 
					
						
							|  |  |  |     node = &chunk->buf[chunk->size++]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   return node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void heap_node_free(Heap *heap, HeapNode *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   node->ptr = heap->nodes.free; | 
					
						
							|  |  |  |   heap->nodes.free = node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \} */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-27 21:32:09 +11:00
										 |  |  | /* -------------------------------------------------------------------- */ | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  | /** \name Public Heap API
 | 
					
						
							|  |  |  |  * \{ */ | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 16:07:07 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Creates a new heap. Removed nodes are recycled, so memory usage will not shrink. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \note Use when the size of the heap is known in advance. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  | Heap *BLI_heap_new_ex(uint tot_reserve) | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |   Heap *heap = MEM_mallocN(sizeof(Heap), __func__); | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  |   /* ensure we have at least one so we can keep doubling it */ | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |   heap->size = 0; | 
					
						
							| 
									
										
										
										
											2013-12-08 17:29:22 +11:00
										 |  |  |   heap->bufsize = MAX2(1u, tot_reserve); | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  |   heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   heap->nodes.chunk = heap_node_alloc_chunk( | 
					
						
							|  |  |  |       (tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL); | 
					
						
							|  |  |  |   heap->nodes.free = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |   return heap; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Heap *BLI_heap_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return BLI_heap_new_ex(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-22 13:00:02 +00:00
										 |  |  |   if (ptrfreefp) { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     uint i; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 13:00:02 +00:00
										 |  |  |     for (i = 0; i < heap->size; i++) { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |       ptrfreefp(heap->tree[i]->ptr); | 
					
						
							| 
									
										
										
										
											2012-10-22 13:00:02 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   struct HeapNode_Chunk *chunk = heap->nodes.chunk; | 
					
						
							|  |  |  |   do { | 
					
						
							|  |  |  |     struct HeapNode_Chunk *chunk_prev; | 
					
						
							|  |  |  |     chunk_prev = chunk->prev; | 
					
						
							|  |  |  |     MEM_freeN(chunk); | 
					
						
							|  |  |  |     chunk = chunk_prev; | 
					
						
							|  |  |  |   } while (chunk); | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |   MEM_freeN(heap->tree); | 
					
						
							|  |  |  |   MEM_freeN(heap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 00:32:20 +01:00
										 |  |  | void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (ptrfreefp) { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     uint i; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 00:32:20 +01:00
										 |  |  |     for (i = 0; i < heap->size; i++) { | 
					
						
							|  |  |  |       ptrfreefp(heap->tree[i]->ptr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   heap->size = 0; | 
					
						
							| 
									
										
										
										
											2019-04-17 06:17:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   /* Remove all except the last chunk */ | 
					
						
							|  |  |  |   while (heap->nodes.chunk->prev) { | 
					
						
							|  |  |  |     struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev; | 
					
						
							|  |  |  |     MEM_freeN(heap->nodes.chunk); | 
					
						
							|  |  |  |     heap->nodes.chunk = chunk_prev; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   heap->nodes.chunk->size = 0; | 
					
						
							|  |  |  |   heap->nodes.free = NULL; | 
					
						
							| 
									
										
										
										
											2014-12-09 00:32:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 16:07:07 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Insert heap node with a value (often a 'cost') and pointer into the heap, | 
					
						
							|  |  |  |  * duplicate values are allowed. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   HeapNode *node; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 22:04:47 +00:00
										 |  |  |   if (UNLIKELY(heap->size >= heap->bufsize)) { | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  |     heap->bufsize *= 2; | 
					
						
							| 
									
										
										
										
											2012-10-22 07:57:21 +00:00
										 |  |  |     heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree)); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   node = heap_node_alloc(heap); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   node->ptr = ptr; | 
					
						
							| 
									
										
										
										
											2015-04-14 18:24:40 +10:00
										 |  |  |   node->value = value; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   node->index = heap->size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   heap->tree[node->index] = node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   heap->size++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-03 22:04:47 +00:00
										 |  |  |   heap_up(heap, node->index); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 15:25:13 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Convenience function since this is a common pattern. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (*node_p == NULL) { | 
					
						
							|  |  |  |     *node_p = BLI_heap_insert(heap, value, ptr); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     BLI_heap_node_value_update_ptr(heap, *node_p, value, ptr); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 15:42:54 +11:00
										 |  |  | bool BLI_heap_is_empty(const Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return (heap->size == 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 23:36:11 +11:00
										 |  |  | uint BLI_heap_len(const Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return heap->size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 16:07:07 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Return the top node of the heap. | 
					
						
							|  |  |  |  * This is the node with the lowest value. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-10-29 15:42:54 +11:00
										 |  |  | HeapNode *BLI_heap_top(const Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return heap->tree[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 13:27:10 +03:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Return the value of top node of the heap. | 
					
						
							|  |  |  |  * This is the node with the lowest value. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | float BLI_heap_top_value(const Heap *heap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   BLI_assert(heap->size != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return heap->tree[0]->value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 16:07:07 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Pop the top node off the heap and return its pointer. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-02-15 23:36:11 +11:00
										 |  |  | void *BLI_heap_pop_min(Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-20 19:09:18 +00:00
										 |  |  |   BLI_assert(heap->size != 0); | 
					
						
							| 
									
										
										
										
											2013-06-19 19:59:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |   void *ptr = heap->tree[0]->ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 19:02:01 +10:00
										 |  |  |   heap_node_free(heap, heap->tree[0]); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-09 00:13:35 +01:00
										 |  |  |   if (--heap->size) { | 
					
						
							|  |  |  |     heap_swap(heap, 0, heap->size); | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |     heap_down(heap, 0); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BLI_heap_remove(Heap *heap, HeapNode *node) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-03 22:04:47 +00:00
										 |  |  |   BLI_assert(heap->size != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |   uint i = node->index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |   while (i > 0) { | 
					
						
							| 
									
										
										
										
											2017-10-28 17:48:45 +11:00
										 |  |  |     uint p = HEAP_PARENT(i); | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  |     heap_swap(heap, p, i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |     i = p; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-15 23:36:11 +11:00
										 |  |  |   BLI_heap_pop_min(heap); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 15:25:13 +11:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls, | 
					
						
							|  |  |  |  * balancing the tree still has a performance cost, | 
					
						
							| 
									
										
										
										
											2019-07-07 15:38:41 +10:00
										 |  |  |  * but is often much less than remove/insert, difference is most noticeable with large heaps. | 
					
						
							| 
									
										
										
										
											2017-10-29 15:25:13 +11:00
										 |  |  |  */ | 
					
						
							|  |  |  | void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |   if (value < node->value) { | 
					
						
							|  |  |  |     node->value = value; | 
					
						
							|  |  |  |     heap_up(heap, node->index); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (value > node->value) { | 
					
						
							|  |  |  |     node->value = value; | 
					
						
							|  |  |  |     heap_down(heap, node->index); | 
					
						
							| 
									
										
										
										
											2017-10-29 15:25:13 +11:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |   node->ptr = ptr; /* only difference */ | 
					
						
							|  |  |  |   if (value < node->value) { | 
					
						
							|  |  |  |     node->value = value; | 
					
						
							|  |  |  |     heap_up(heap, node->index); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else if (value > node->value) { | 
					
						
							|  |  |  |     node->value = value; | 
					
						
							|  |  |  |     heap_down(heap, node->index); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-10-29 15:25:13 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-04 20:59:13 +02:00
										 |  |  | float BLI_heap_node_value(const HeapNode *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-04 20:59:13 +02:00
										 |  |  |   return heap->value; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-04 20:59:13 +02:00
										 |  |  | void *BLI_heap_node_ptr(const HeapNode *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-09-04 20:59:13 +02:00
										 |  |  |   return heap->ptr; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  | static bool heap_is_minheap(const Heap *heap, uint root) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (root < heap->size) { | 
					
						
							| 
									
										
										
										
											2018-11-04 12:17:09 +03:00
										 |  |  |     if (heap->tree[root]->index != root) { | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2017-10-29 18:23:33 +11:00
										 |  |  |     const uint l = HEAP_LEFT(root); | 
					
						
							|  |  |  |     if (l < heap->size) { | 
					
						
							|  |  |  |       if (HEAP_COMPARE(heap->tree[l], heap->tree[root]) || !heap_is_minheap(heap, l)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const uint r = HEAP_RIGHT(root); | 
					
						
							|  |  |  |     if (r < heap->size) { | 
					
						
							|  |  |  |       if (HEAP_COMPARE(heap->tree[r], heap->tree[root]) || !heap_is_minheap(heap, r)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Only for checking internal errors (gtest). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | bool BLI_heap_is_valid(const Heap *heap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return heap_is_minheap(heap, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-17 17:31:27 +10:00
										 |  |  | /** \} */ |