| 
									
										
										
										
											2011-02-23 10:52:22 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-04-16 22:40:48 +00:00
										 |  |  |  * ***** BEGIN GPL LICENSE BLOCK ***** | 
					
						
							| 
									
										
										
										
											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
										 |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is: none of this file. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributor(s): Brecht Van Lommel | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-04-16 22:40:48 +00:00
										 |  |  |  * ***** END GPL LICENSE BLOCK ***** | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  |  * A heap / priority queue ADT. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-27 20:37:56 +00:00
										 |  |  | /** \file blender/blenlib/intern/BLI_heap.c
 | 
					
						
							|  |  |  |  *  \ingroup bli | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | #include "BLI_memarena.h"
 | 
					
						
							|  |  |  | #include "BLI_heap.h"
 | 
					
						
							| 
									
										
										
										
											2012-03-12 07:21:22 +00:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct HeapNode { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 	void        *ptr; | 
					
						
							|  |  |  | 	float        value; | 
					
						
							|  |  |  | 	unsigned int index; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Heap { | 
					
						
							|  |  |  | 	unsigned int size; | 
					
						
							|  |  |  | 	unsigned int bufsize; | 
					
						
							|  |  |  | 	MemArena *arena; | 
					
						
							|  |  |  | 	HeapNode *freenodes; | 
					
						
							|  |  |  | 	HeapNode *nodes; | 
					
						
							|  |  |  | 	HeapNode **tree; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | /* internal functions */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-11 23:47:41 +00:00
										 |  |  | #define HEAP_PARENT(i) ((i - 1) >> 1)
 | 
					
						
							|  |  |  | #define HEAP_LEFT(i)   ((i << 1) + 1)
 | 
					
						
							|  |  |  | #define HEAP_RIGHT(i)  ((i << 1) + 2)
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | #define HEAP_COMPARE(a, b) (a->value < b->value)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | #if 0  /* UNUSED */
 | 
					
						
							|  |  |  | #define HEAP_EQUALS(a, b) (a->value == b->value)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | BLI_INLINE void heap_swap(Heap *heap, const unsigned int i, const unsigned int j) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | #if 0
 | 
					
						
							|  |  |  | 	SWAP(unsigned int,  heap->tree[i]->index, heap->tree[j]->index); | 
					
						
							|  |  |  | 	SWAP(HeapNode *,    heap->tree[i],        heap->tree[j]); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	HeapNode **tree = heap->tree; | 
					
						
							|  |  |  | 	union { | 
					
						
							|  |  |  | 		unsigned int  index; | 
					
						
							|  |  |  | 		HeapNode     *node; | 
					
						
							|  |  |  | 	} tmp; | 
					
						
							|  |  |  | 	SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index); | 
					
						
							|  |  |  | 	SWAP_TVAL(tmp.node,  tree[i],        tree[j]); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | static void heap_down(Heap *heap, unsigned int i) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		unsigned int size = heap->size,smallest ; | 
					
						
							|  |  |  | 		unsigned int l = HEAP_LEFT(i); | 
					
						
							|  |  |  | 		unsigned int r = HEAP_RIGHT(i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-11 23:47:41 +00:00
										 |  |  | 		smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) | 
					
						
							|  |  |  | 			smallest = r; | 
					
						
							| 
									
										
										
										
											2012-03-11 23:47:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		if (smallest == i) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		heap_swap(heap, i, smallest); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		i = smallest; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | static void heap_up(Heap *heap, unsigned int i) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	while (i > 0) { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		unsigned int p = HEAP_PARENT(i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		heap_swap(heap, p, i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		i = p; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* use when the size of the heap is known in advance */ | 
					
						
							|  |  |  | Heap *BLI_heap_new_ex(unsigned int tot_reserve) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Heap *heap = (Heap *)MEM_callocN(sizeof(Heap), __func__); | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  | 	/* ensure we have at least one so we can keep doubling it */ | 
					
						
							| 
									
										
										
										
											2012-10-22 07:57:21 +00:00
										 |  |  | 	heap->bufsize = MAX2(1, tot_reserve); | 
					
						
							|  |  |  | 	heap->tree = (HeapNode **)MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 	heap->arena = BLI_memarena_new(1 << 16, "heap arena"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return heap; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Heap *BLI_heap_new(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return BLI_heap_new_ex(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ptrfreefp) | 
					
						
							|  |  |  | 		for (i = 0; i < heap->size; i++) | 
					
						
							|  |  |  | 			ptrfreefp(heap->tree[i]->ptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	MEM_freeN(heap->tree); | 
					
						
							|  |  |  | 	BLI_memarena_free(heap->arena); | 
					
						
							|  |  |  | 	MEM_freeN(heap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	HeapNode *node; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  | 	if (UNLIKELY((heap->size + 1) > heap->bufsize)) { | 
					
						
							|  |  |  | 		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
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (heap->freenodes) { | 
					
						
							|  |  |  | 		node = heap->freenodes; | 
					
						
							| 
									
										
										
										
											2012-03-11 23:47:41 +00:00
										 |  |  | 		heap->freenodes = (HeapNode *)(((HeapNode *)heap->freenodes)->ptr); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-10-22 07:57:21 +00:00
										 |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2012-03-11 23:47:41 +00:00
										 |  |  | 		node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof *node); | 
					
						
							| 
									
										
										
										
											2012-10-22 07:57:21 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	node->value = value; | 
					
						
							|  |  |  | 	node->ptr = ptr; | 
					
						
							|  |  |  | 	node->index = heap->size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	heap->tree[node->index] = node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	heap->size++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 	heap_up(heap, heap->size - 1); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-21 15:20:53 +00:00
										 |  |  | int BLI_heap_is_empty(Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return (heap->size == 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | unsigned int BLI_heap_size(Heap *heap) | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return heap->size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HeapNode *BLI_heap_top(Heap *heap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return heap->tree[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *BLI_heap_popmin(Heap *heap) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	void *ptr = heap->tree[0]->ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	heap->tree[0]->ptr = heap->freenodes; | 
					
						
							|  |  |  | 	heap->freenodes = heap->tree[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  | 	if (UNLIKELY(heap->size == 1)) { | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		heap->size--; | 
					
						
							| 
									
										
										
										
											2012-10-22 08:15:51 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		heap_swap(heap, 0, heap->size - 1); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 	unsigned int i = node->index; | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (i > 0) { | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		unsigned int p = HEAP_PARENT(i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-22 03:25:53 +00:00
										 |  |  | 		heap_swap(heap, p, i); | 
					
						
							| 
									
										
										
										
											2006-02-08 18:06:35 +00:00
										 |  |  | 		i = p; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BLI_heap_popmin(heap); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float BLI_heap_node_value(HeapNode *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return node->value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *BLI_heap_node_ptr(HeapNode *node) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return node->ptr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |