1/* 2 * Copyright (C) 2004-2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1997-2001 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file 21 * Heap implementation of priority queues adapted from the following: 22 * 23 * \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest, 24 * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7. 25 * 26 * \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988, 27 * ISBN 0-201-06673-4, chapter 11. 28 */ 29 30#include <config.h> 31 32#include <isc/heap.h> 33#include <isc/magic.h> 34#include <isc/mem.h> 35#include <isc/string.h> /* Required for memcpy. */ 36#include <isc/util.h> 37 38/*@{*/ 39/*% 40 * Note: to make heap_parent and heap_left easy to compute, the first 41 * element of the heap array is not used; i.e. heap subscripts are 1-based, 42 * not 0-based. The parent is index/2, and the left-child is index*2. 43 * The right child is index*2+1. 44 */ 45#define heap_parent(i) ((i) >> 1) 46#define heap_left(i) ((i) << 1) 47/*@}*/ 48 49#define SIZE_INCREMENT 1024 50 51#define HEAP_MAGIC ISC_MAGIC('H', 'E', 'A', 'P') 52#define VALID_HEAP(h) ISC_MAGIC_VALID(h, HEAP_MAGIC) 53 54/*% 55 * When the heap is in a consistent state, the following invariant 56 * holds true: for every element i > 1, heap_parent(i) has a priority 57 * higher than or equal to that of i. 58 */ 59#define HEAPCONDITION(i) ((i) == 1 || \ 60 ! heap->compare(heap->array[(i)], \ 61 heap->array[heap_parent(i)])) 62 63/*% ISC heap structure. */ 64struct isc_heap { 65 unsigned int magic; 66 isc_mem_t * mctx; 67 unsigned int size; 68 unsigned int size_increment; 69 unsigned int last; 70 void **array; 71 isc_heapcompare_t compare; 72 isc_heapindex_t index; 73}; 74 75isc_result_t 76isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare, 77 isc_heapindex_t index, unsigned int size_increment, 78 isc_heap_t **heapp) 79{ 80 isc_heap_t *heap; 81 82 REQUIRE(heapp != NULL && *heapp == NULL); 83 REQUIRE(compare != NULL); 84 85 heap = isc_mem_get(mctx, sizeof(*heap)); 86 if (heap == NULL) 87 return (ISC_R_NOMEMORY); 88 heap->magic = HEAP_MAGIC; 89 heap->size = 0; 90 heap->mctx = NULL; 91 isc_mem_attach(mctx, &heap->mctx); 92 if (size_increment == 0) 93 heap->size_increment = SIZE_INCREMENT; 94 else 95 heap->size_increment = size_increment; 96 heap->last = 0; 97 heap->array = NULL; 98 heap->compare = compare; 99 heap->index = index; 100 101 *heapp = heap; 102 103 return (ISC_R_SUCCESS); 104} 105 106void 107isc_heap_destroy(isc_heap_t **heapp) { 108 isc_heap_t *heap; 109 110 REQUIRE(heapp != NULL); 111 heap = *heapp; 112 REQUIRE(VALID_HEAP(heap)); 113 114 if (heap->array != NULL) 115 isc_mem_put(heap->mctx, heap->array, 116 heap->size * sizeof(void *)); 117 heap->magic = 0; 118 isc_mem_putanddetach(&heap->mctx, heap, sizeof(*heap)); 119 120 *heapp = NULL; 121} 122 123static isc_boolean_t 124resize(isc_heap_t *heap) { 125 void **new_array; 126 size_t new_size; 127 128 REQUIRE(VALID_HEAP(heap)); 129 130 new_size = heap->size + heap->size_increment; 131 new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *)); 132 if (new_array == NULL) 133 return (ISC_FALSE); 134 if (heap->array != NULL) { 135 memcpy(new_array, heap->array, heap->size * sizeof(void *)); 136 isc_mem_put(heap->mctx, heap->array, 137 heap->size * sizeof(void *)); 138 } 139 heap->size = new_size; 140 heap->array = new_array; 141 142 return (ISC_TRUE); 143} 144 145static void 146float_up(isc_heap_t *heap, unsigned int i, void *elt) { 147 unsigned int p; 148 149 for (p = heap_parent(i) ; 150 i > 1 && heap->compare(elt, heap->array[p]) ; 151 i = p, p = heap_parent(i)) { 152 heap->array[i] = heap->array[p]; 153 if (heap->index != NULL) 154 (heap->index)(heap->array[i], i); 155 } 156 heap->array[i] = elt; 157 if (heap->index != NULL) 158 (heap->index)(heap->array[i], i); 159 160 INSIST(HEAPCONDITION(i)); 161} 162 163static void 164sink_down(isc_heap_t *heap, unsigned int i, void *elt) { 165 unsigned int j, size, half_size; 166 size = heap->last; 167 half_size = size / 2; 168 while (i <= half_size) { 169 /* Find the smallest of the (at most) two children. */ 170 j = heap_left(i); 171 if (j < size && heap->compare(heap->array[j+1], 172 heap->array[j])) 173 j++; 174 if (heap->compare(elt, heap->array[j])) 175 break; 176 heap->array[i] = heap->array[j]; 177 if (heap->index != NULL) 178 (heap->index)(heap->array[i], i); 179 i = j; 180 } 181 heap->array[i] = elt; 182 if (heap->index != NULL) 183 (heap->index)(heap->array[i], i); 184 185 INSIST(HEAPCONDITION(i)); 186} 187 188isc_result_t 189isc_heap_insert(isc_heap_t *heap, void *elt) { 190 unsigned int new_last; 191 192 REQUIRE(VALID_HEAP(heap)); 193 194 new_last = heap->last + 1; 195 RUNTIME_CHECK(new_last > 0); /* overflow check */ 196 if (new_last >= heap->size && !resize(heap)) 197 return (ISC_R_NOMEMORY); 198 heap->last = new_last; 199 200 float_up(heap, new_last, elt); 201 202 return (ISC_R_SUCCESS); 203} 204 205void 206isc_heap_delete(isc_heap_t *heap, unsigned int index) { 207 void *elt; 208 isc_boolean_t less; 209 210 REQUIRE(VALID_HEAP(heap)); 211 REQUIRE(index >= 1 && index <= heap->last); 212 213 if (index == heap->last) { 214 heap->array[heap->last] = NULL; 215 heap->last--; 216 } else { 217 elt = heap->array[heap->last]; 218 heap->array[heap->last] = NULL; 219 heap->last--; 220 221 less = heap->compare(elt, heap->array[index]); 222 heap->array[index] = elt; 223 if (less) 224 float_up(heap, index, heap->array[index]); 225 else 226 sink_down(heap, index, heap->array[index]); 227 } 228} 229 230void 231isc_heap_increased(isc_heap_t *heap, unsigned int index) { 232 REQUIRE(VALID_HEAP(heap)); 233 REQUIRE(index >= 1 && index <= heap->last); 234 235 float_up(heap, index, heap->array[index]); 236} 237 238void 239isc_heap_decreased(isc_heap_t *heap, unsigned int index) { 240 REQUIRE(VALID_HEAP(heap)); 241 REQUIRE(index >= 1 && index <= heap->last); 242 243 sink_down(heap, index, heap->array[index]); 244} 245 246void * 247isc_heap_element(isc_heap_t *heap, unsigned int index) { 248 REQUIRE(VALID_HEAP(heap)); 249 REQUIRE(index >= 1); 250 251 if (index <= heap->last) 252 return (heap->array[index]); 253 return (NULL); 254} 255 256void 257isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) { 258 unsigned int i; 259 260 REQUIRE(VALID_HEAP(heap)); 261 REQUIRE(action != NULL); 262 263 for (i = 1 ; i <= heap->last ; i++) 264 (action)(heap->array[i], uap); 265} 266