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