/* * Copyright (c) 2016, Blender Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** \file generic_heap.c * \ingroup curve_fit */ #include #include #include #include #include "generic_heap.h" /* swap with a temp value */ #define SWAP_TVAL(tval, a, b) { \ (tval) = (a); \ (a) = (b); \ (b) = (tval); \ } (void)0 #ifdef __GNUC__ # define UNLIKELY(x) __builtin_expect(!!(x), 0) #else # define UNLIKELY(x) (x) #endif typedef unsigned int uint; /***/ struct HeapNode { void *ptr; double value; uint index; }; /* heap_* pool allocator */ #define TPOOL_IMPL_PREFIX heap #define TPOOL_ALLOC_TYPE HeapNode #define TPOOL_STRUCT HeapMemPool #include "generic_alloc_impl.h" #undef TPOOL_IMPL_PREFIX #undef TPOOL_ALLOC_TYPE #undef TPOOL_STRUCT struct Heap { uint size; uint bufsize; HeapNode **tree; struct HeapMemPool pool; }; /** \name Internal Functions * \{ */ #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) #if 0 /* UNUSED */ #define HEAP_EQUALS(a, b) ((a)->value == (b)->value) #endif static void heap_swap(Heap *heap, const uint i, const uint j) { #if 0 SWAP(uint, heap->tree[i]->index, heap->tree[j]->index); SWAP(HeapNode *, heap->tree[i], heap->tree[j]); #else HeapNode **tree = heap->tree; union { uint index; HeapNode *node; } tmp; SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index); SWAP_TVAL(tmp.node, tree[i], tree[j]); #endif } static void heap_down(Heap *heap, uint i) { /* size won't change in the loop */ const uint size = heap->size; while (1) { const uint l = HEAP_LEFT(i); const uint r = HEAP_RIGHT(i); uint smallest; smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i; if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) { smallest = r; } if (smallest == i) { break; } heap_swap(heap, i, smallest); i = smallest; } } static void heap_up(Heap *heap, uint i) { while (i > 0) { const uint p = HEAP_PARENT(i); if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) { break; } heap_swap(heap, p, i); i = p; } } /** \} */ /** \name Public Heap API * \{ */ /* use when the size of the heap is known in advance */ Heap *HEAP_new(uint tot_reserve) { Heap *heap = malloc(sizeof(Heap)); /* ensure we have at least one so we can keep doubling it */ heap->size = 0; heap->bufsize = tot_reserve ? tot_reserve : 1; heap->tree = malloc(heap->bufsize * sizeof(HeapNode *)); heap_pool_create(&heap->pool, tot_reserve); return heap; } void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp) { if (ptrfreefp) { uint i; for (i = 0; i < heap->size; i++) { ptrfreefp(heap->tree[i]->ptr); } } heap_pool_destroy(&heap->pool); free(heap->tree); free(heap); } void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp) { if (ptrfreefp) { uint i; for (i = 0; i < heap->size; i++) { ptrfreefp(heap->tree[i]->ptr); } } heap->size = 0; heap_pool_clear(&heap->pool); } HeapNode *HEAP_insert(Heap *heap, double value, void *ptr) { HeapNode *node; if (UNLIKELY(heap->size >= heap->bufsize)) { heap->bufsize *= 2; heap->tree = realloc(heap->tree, heap->bufsize * sizeof(*heap->tree)); } node = heap_pool_elem_alloc(&heap->pool); node->ptr = ptr; node->value = value; node->index = heap->size; heap->tree[node->index] = node; heap->size++; heap_up(heap, node->index); return node; } void HEAP_insert_or_update(Heap *heap, HeapNode **node_p, double value, void *ptr) { if (*node_p == NULL) { *node_p = HEAP_insert(heap, value, ptr); } else { HEAP_node_value_update_ptr(heap, *node_p, value, ptr); } } bool HEAP_is_empty(const Heap *heap) { return (heap->size == 0); } uint HEAP_size(const Heap *heap) { return heap->size; } HeapNode *HEAP_top(Heap *heap) { return heap->tree[0]; } double HEAP_top_value(const Heap *heap) { return heap->tree[0]->value; } void *HEAP_popmin(Heap *heap) { void *ptr = heap->tree[0]->ptr; assert(heap->size != 0); heap_pool_elem_free(&heap->pool, heap->tree[0]); if (--heap->size) { heap_swap(heap, 0, heap->size); heap_down(heap, 0); } return ptr; } void HEAP_remove(Heap *heap, HeapNode *node) { uint i = node->index; assert(heap->size != 0); while (i > 0) { uint p = HEAP_PARENT(i); heap_swap(heap, p, i); i = p; } HEAP_popmin(heap); } void HEAP_node_value_update(Heap *heap, HeapNode *node, double value) { assert(heap->size != 0); if (node->value == value) { return; } node->value = value; /* Can be called in either order, makes no difference. */ heap_up(heap, node->index); heap_down(heap, node->index); } void HEAP_node_value_update_ptr(Heap *heap, HeapNode *node, double value, void *ptr) { node->ptr = ptr; HEAP_node_value_update(heap, node, value); } double HEAP_node_value(const HeapNode *node) { return node->value; } void *HEAP_node_ptr(HeapNode *node) { return node->ptr; }