15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
17*1fb015a8Sflorian /* $Id: heap.c,v 1.7 2020/09/14 08:40:44 florian Exp $ */
185185a700Sflorian
195185a700Sflorian /*! \file
205185a700Sflorian * Heap implementation of priority queues adapted from the following:
215185a700Sflorian *
225185a700Sflorian * \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest,
235185a700Sflorian * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
245185a700Sflorian *
255185a700Sflorian * \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988,
265185a700Sflorian * ISBN 0-201-06673-4, chapter 11.
275185a700Sflorian */
285185a700Sflorian
295185a700Sflorian #include <stdlib.h>
305185a700Sflorian #include <isc/heap.h>
315185a700Sflorian #include <string.h>
325185a700Sflorian #include <isc/util.h>
335185a700Sflorian
345185a700Sflorian /*@{*/
355185a700Sflorian /*%
365185a700Sflorian * Note: to make heap_parent and heap_left easy to compute, the first
375185a700Sflorian * element of the heap array is not used; i.e. heap subscripts are 1-based,
385185a700Sflorian * not 0-based. The parent is index/2, and the left-child is index*2.
395185a700Sflorian * The right child is index*2+1.
405185a700Sflorian */
415185a700Sflorian #define heap_parent(i) ((i) >> 1)
425185a700Sflorian #define heap_left(i) ((i) << 1)
435185a700Sflorian /*@}*/
445185a700Sflorian
455185a700Sflorian #define SIZE_INCREMENT 1024
465185a700Sflorian
475185a700Sflorian /*%
485185a700Sflorian * When the heap is in a consistent state, the following invariant
495185a700Sflorian * holds true: for every element i > 1, heap_parent(i) has a priority
505185a700Sflorian * higher than or equal to that of i.
515185a700Sflorian */
525185a700Sflorian #define HEAPCONDITION(i) ((i) == 1 || \
535185a700Sflorian ! heap->compare(heap->array[(i)], \
545185a700Sflorian heap->array[heap_parent(i)]))
555185a700Sflorian
565185a700Sflorian /*% ISC heap structure. */
575185a700Sflorian struct isc_heap {
585185a700Sflorian unsigned int size;
595185a700Sflorian unsigned int size_increment;
605185a700Sflorian unsigned int last;
615185a700Sflorian void **array;
625185a700Sflorian isc_heapcompare_t compare;
635185a700Sflorian isc_heapindex_t index;
645185a700Sflorian };
655185a700Sflorian
665185a700Sflorian isc_result_t
isc_heap_create(isc_heapcompare_t compare,isc_heapindex_t idx,unsigned int size_increment,isc_heap_t ** heapp)675185a700Sflorian isc_heap_create(isc_heapcompare_t compare,
685185a700Sflorian isc_heapindex_t idx, unsigned int size_increment,
695185a700Sflorian isc_heap_t **heapp)
705185a700Sflorian {
715185a700Sflorian isc_heap_t *heap;
725185a700Sflorian
735185a700Sflorian REQUIRE(heapp != NULL && *heapp == NULL);
745185a700Sflorian REQUIRE(compare != NULL);
755185a700Sflorian
765185a700Sflorian heap = malloc(sizeof(*heap));
775185a700Sflorian if (heap == NULL)
785185a700Sflorian return (ISC_R_NOMEMORY);
795185a700Sflorian heap->size = 0;
805185a700Sflorian if (size_increment == 0)
815185a700Sflorian heap->size_increment = SIZE_INCREMENT;
825185a700Sflorian else
835185a700Sflorian heap->size_increment = size_increment;
845185a700Sflorian heap->last = 0;
855185a700Sflorian heap->array = NULL;
865185a700Sflorian heap->compare = compare;
875185a700Sflorian heap->index = idx;
885185a700Sflorian
895185a700Sflorian *heapp = heap;
905185a700Sflorian
915185a700Sflorian return (ISC_R_SUCCESS);
925185a700Sflorian }
935185a700Sflorian
945185a700Sflorian void
isc_heap_destroy(isc_heap_t ** heapp)955185a700Sflorian isc_heap_destroy(isc_heap_t **heapp) {
965185a700Sflorian isc_heap_t *heap;
975185a700Sflorian
985185a700Sflorian REQUIRE(heapp != NULL);
995185a700Sflorian heap = *heapp;
1005185a700Sflorian
1015185a700Sflorian free(heap->array);
1025185a700Sflorian free(heap);
1035185a700Sflorian
1045185a700Sflorian *heapp = NULL;
1055185a700Sflorian }
1065185a700Sflorian
107*1fb015a8Sflorian static int
resize(isc_heap_t * heap)1085185a700Sflorian resize(isc_heap_t *heap) {
1095185a700Sflorian void **new_array;
1105185a700Sflorian unsigned int new_size;
1115185a700Sflorian
1125185a700Sflorian new_size = heap->size + heap->size_increment;
1135148cc0dSderaadt new_array = reallocarray(NULL, new_size, sizeof(void *));
1145185a700Sflorian if (new_array == NULL)
115*1fb015a8Sflorian return (0);
1165185a700Sflorian if (heap->array != NULL) {
1175185a700Sflorian memmove(new_array, heap->array, heap->size * sizeof(void *));
1185185a700Sflorian free(heap->array);
1195185a700Sflorian }
1205185a700Sflorian heap->size = new_size;
1215185a700Sflorian heap->array = new_array;
1225185a700Sflorian
123*1fb015a8Sflorian return (1);
1245185a700Sflorian }
1255185a700Sflorian
1265185a700Sflorian static void
float_up(isc_heap_t * heap,unsigned int i,void * elt)1275185a700Sflorian float_up(isc_heap_t *heap, unsigned int i, void *elt) {
1285185a700Sflorian unsigned int p;
1295185a700Sflorian
1305185a700Sflorian for (p = heap_parent(i) ;
1315185a700Sflorian i > 1 && heap->compare(elt, heap->array[p]) ;
1325185a700Sflorian i = p, p = heap_parent(i)) {
1335185a700Sflorian heap->array[i] = heap->array[p];
1345185a700Sflorian if (heap->index != NULL)
1355185a700Sflorian (heap->index)(heap->array[i], i);
1365185a700Sflorian }
1375185a700Sflorian heap->array[i] = elt;
1385185a700Sflorian if (heap->index != NULL)
1395185a700Sflorian (heap->index)(heap->array[i], i);
1405185a700Sflorian
1415185a700Sflorian INSIST(HEAPCONDITION(i));
1425185a700Sflorian }
1435185a700Sflorian
1445185a700Sflorian static void
sink_down(isc_heap_t * heap,unsigned int i,void * elt)1455185a700Sflorian sink_down(isc_heap_t *heap, unsigned int i, void *elt) {
1465185a700Sflorian unsigned int j, size, half_size;
1475185a700Sflorian size = heap->last;
1485185a700Sflorian half_size = size / 2;
1495185a700Sflorian while (i <= half_size) {
1505185a700Sflorian /* Find the smallest of the (at most) two children. */
1515185a700Sflorian j = heap_left(i);
1525185a700Sflorian if (j < size && heap->compare(heap->array[j+1],
1535185a700Sflorian heap->array[j]))
1545185a700Sflorian j++;
1555185a700Sflorian if (heap->compare(elt, heap->array[j]))
1565185a700Sflorian break;
1575185a700Sflorian heap->array[i] = heap->array[j];
1585185a700Sflorian if (heap->index != NULL)
1595185a700Sflorian (heap->index)(heap->array[i], i);
1605185a700Sflorian i = j;
1615185a700Sflorian }
1625185a700Sflorian heap->array[i] = elt;
1635185a700Sflorian if (heap->index != NULL)
1645185a700Sflorian (heap->index)(heap->array[i], i);
1655185a700Sflorian
1665185a700Sflorian INSIST(HEAPCONDITION(i));
1675185a700Sflorian }
1685185a700Sflorian
1695185a700Sflorian isc_result_t
isc_heap_insert(isc_heap_t * heap,void * elt)1705185a700Sflorian isc_heap_insert(isc_heap_t *heap, void *elt) {
1715185a700Sflorian unsigned int new_last;
1725185a700Sflorian
1735185a700Sflorian new_last = heap->last + 1;
1745185a700Sflorian RUNTIME_CHECK(new_last > 0); /* overflow check */
1755185a700Sflorian if (new_last >= heap->size && !resize(heap))
1765185a700Sflorian return (ISC_R_NOMEMORY);
1775185a700Sflorian heap->last = new_last;
1785185a700Sflorian
1795185a700Sflorian float_up(heap, new_last, elt);
1805185a700Sflorian
1815185a700Sflorian return (ISC_R_SUCCESS);
1825185a700Sflorian }
1835185a700Sflorian
1845185a700Sflorian void
isc_heap_delete(isc_heap_t * heap,unsigned int idx)1855185a700Sflorian isc_heap_delete(isc_heap_t *heap, unsigned int idx) {
1865185a700Sflorian void *elt;
187*1fb015a8Sflorian int less;
1885185a700Sflorian
1895185a700Sflorian REQUIRE(idx >= 1 && idx <= heap->last);
1905185a700Sflorian
1915185a700Sflorian if (heap->index != NULL)
1925185a700Sflorian (heap->index)(heap->array[idx], 0);
1935185a700Sflorian if (idx == heap->last) {
1945185a700Sflorian heap->array[heap->last] = NULL;
1955185a700Sflorian heap->last--;
1965185a700Sflorian } else {
1975185a700Sflorian elt = heap->array[heap->last];
1985185a700Sflorian heap->array[heap->last] = NULL;
1995185a700Sflorian heap->last--;
2005185a700Sflorian
2015185a700Sflorian less = heap->compare(elt, heap->array[idx]);
2025185a700Sflorian heap->array[idx] = elt;
2035185a700Sflorian if (less)
2045185a700Sflorian float_up(heap, idx, heap->array[idx]);
2055185a700Sflorian else
2065185a700Sflorian sink_down(heap, idx, heap->array[idx]);
2075185a700Sflorian }
2085185a700Sflorian }
2095185a700Sflorian
2105185a700Sflorian void
isc_heap_increased(isc_heap_t * heap,unsigned int idx)2115185a700Sflorian isc_heap_increased(isc_heap_t *heap, unsigned int idx) {
2125185a700Sflorian REQUIRE(idx >= 1 && idx <= heap->last);
2135185a700Sflorian
2145185a700Sflorian float_up(heap, idx, heap->array[idx]);
2155185a700Sflorian }
2165185a700Sflorian
2175185a700Sflorian void
isc_heap_decreased(isc_heap_t * heap,unsigned int idx)2185185a700Sflorian isc_heap_decreased(isc_heap_t *heap, unsigned int idx) {
2195185a700Sflorian REQUIRE(idx >= 1 && idx <= heap->last);
2205185a700Sflorian
2215185a700Sflorian sink_down(heap, idx, heap->array[idx]);
2225185a700Sflorian }
2235185a700Sflorian
2245185a700Sflorian void *
isc_heap_element(isc_heap_t * heap,unsigned int idx)2255185a700Sflorian isc_heap_element(isc_heap_t *heap, unsigned int idx) {
2265185a700Sflorian REQUIRE(idx >= 1);
2275185a700Sflorian
2285185a700Sflorian if (idx <= heap->last)
2295185a700Sflorian return (heap->array[idx]);
2305185a700Sflorian return (NULL);
2315185a700Sflorian }
232