xref: /openbsd-src/usr.bin/dig/lib/isc/heap.c (revision 1fb015a8af3a7e9b85db2510147a155826ef04d9)
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