xref: /netbsd-src/external/bsd/libbind/dist/isc/heap.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: heap.c,v 1.1.1.2 2012/09/09 16:08:00 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1997,1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and 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
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*%
21  * Heap implementation of priority queues adapted from the following:
22  *
23  *	_Introduction to Algorithms_, Cormen, Leiserson, and Rivest,
24  *	MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7.
25  *
26  *	_Algorithms_, Second Edition, Sedgewick, Addison-Wesley, 1988,
27  *	ISBN 0-201-06673-4, chapter 11.
28  */
29 
30 #if !defined(LINT) && !defined(CODECENTER)
31 static const char rcsid[] = "Id: heap.c,v 1.4 2006/03/09 23:57:56 marka Exp ";
32 #endif /* not lint */
33 
34 #include "port_before.h"
35 
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <errno.h>
39 
40 #include "port_after.h"
41 
42 #include <isc/heap.h>
43 
44 /*%
45  * Note: to make heap_parent and heap_left easy to compute, the first
46  * element of the heap array is not used; i.e. heap subscripts are 1-based,
47  * not 0-based.
48  */
49 #define heap_parent(i) ((i) >> 1)
50 #define heap_left(i) ((i) << 1)
51 
52 #define ARRAY_SIZE_INCREMENT 512
53 
54 heap_context
55 heap_new(heap_higher_priority_func higher_priority, heap_index_func index,
56 	 int array_size_increment) {
57 	heap_context ctx;
58 
59 	if (higher_priority == NULL)
60 		return (NULL);
61 
62 	ctx = (heap_context)malloc(sizeof (struct heap_context));
63 	if (ctx == NULL)
64 		return (NULL);
65 
66 	ctx->array_size = 0;
67 	if (array_size_increment == 0)
68 		ctx->array_size_increment = ARRAY_SIZE_INCREMENT;
69 	else
70 		ctx->array_size_increment = array_size_increment;
71 	ctx->heap_size = 0;
72 	ctx->heap = NULL;
73 	ctx->higher_priority = higher_priority;
74 	ctx->index = index;
75 	return (ctx);
76 }
77 
78 int
79 heap_free(heap_context ctx) {
80 	if (ctx == NULL) {
81 		errno = EINVAL;
82 		return (-1);
83 	}
84 
85 	if (ctx->heap != NULL)
86 		free(ctx->heap);
87 	free(ctx);
88 
89 	return (0);
90 }
91 
92 static int
93 heap_resize(heap_context ctx) {
94 	void **new_heap;
95 
96 	ctx->array_size += ctx->array_size_increment;
97 	new_heap = (void **)realloc(ctx->heap,
98 				    (ctx->array_size) * (sizeof (void *)));
99 	if (new_heap == NULL) {
100 		errno = ENOMEM;
101 		return (-1);
102 	}
103 	ctx->heap = new_heap;
104 	return (0);
105 }
106 
107 static void
108 float_up(heap_context ctx, int i, void *elt) {
109 	int p;
110 
111 	for ( p = heap_parent(i);
112 	      i > 1 && ctx->higher_priority(elt, ctx->heap[p]);
113 	      i = p, p = heap_parent(i) ) {
114 		ctx->heap[i] = ctx->heap[p];
115 		if (ctx->index != NULL)
116 			(ctx->index)(ctx->heap[i], i);
117 	}
118 	ctx->heap[i] = elt;
119 	if (ctx->index != NULL)
120 		(ctx->index)(ctx->heap[i], i);
121 }
122 
123 static void
124 sink_down(heap_context ctx, int i, void *elt) {
125 	int j, size, half_size;
126 
127 	size = ctx->heap_size;
128 	half_size = size / 2;
129 	while (i <= half_size) {
130 		/* find smallest of the (at most) two children */
131 		j = heap_left(i);
132 		if (j < size && ctx->higher_priority(ctx->heap[j+1],
133 						     ctx->heap[j]))
134 			j++;
135 		if (ctx->higher_priority(elt, ctx->heap[j]))
136 			break;
137 		ctx->heap[i] = ctx->heap[j];
138 		if (ctx->index != NULL)
139 			(ctx->index)(ctx->heap[i], i);
140 		i = j;
141 	}
142 	ctx->heap[i] = elt;
143 	if (ctx->index != NULL)
144 		(ctx->index)(ctx->heap[i], i);
145 }
146 
147 int
148 heap_insert(heap_context ctx, void *elt) {
149 	int i;
150 
151 	if (ctx == NULL || elt == NULL) {
152 		errno = EINVAL;
153 		return (-1);
154 	}
155 
156 	i = ++ctx->heap_size;
157 	if (ctx->heap_size >= ctx->array_size && heap_resize(ctx) < 0)
158 		return (-1);
159 
160 	float_up(ctx, i, elt);
161 
162 	return (0);
163 }
164 
165 int
166 heap_delete(heap_context ctx, int i) {
167 	void *elt;
168 	int less;
169 
170 	if (ctx == NULL || i < 1 || i > ctx->heap_size) {
171 		errno = EINVAL;
172 		return (-1);
173 	}
174 
175 	if (i == ctx->heap_size) {
176 		ctx->heap_size--;
177 	} else {
178 		elt = ctx->heap[ctx->heap_size--];
179 		less = ctx->higher_priority(elt, ctx->heap[i]);
180 		ctx->heap[i] = elt;
181 		if (less)
182 			float_up(ctx, i, ctx->heap[i]);
183 		else
184 			sink_down(ctx, i, ctx->heap[i]);
185 	}
186 
187 	return (0);
188 }
189 
190 int
191 heap_increased(heap_context ctx, int i) {
192      	if (ctx == NULL || i < 1 || i > ctx->heap_size) {
193 		errno = EINVAL;
194 		return (-1);
195 	}
196 
197 	float_up(ctx, i, ctx->heap[i]);
198 
199 	return (0);
200 }
201 
202 int
203 heap_decreased(heap_context ctx, int i) {
204      	if (ctx == NULL || i < 1 || i > ctx->heap_size) {
205 		errno = EINVAL;
206 		return (-1);
207 	}
208 
209 	sink_down(ctx, i, ctx->heap[i]);
210 
211 	return (0);
212 }
213 
214 void *
215 heap_element(heap_context ctx, int i) {
216 	if (ctx == NULL || i < 1 || i > ctx->heap_size) {
217 		errno = EINVAL;
218 		return (NULL);
219 	}
220 
221 	return (ctx->heap[i]);
222 }
223 
224 int
225 heap_for_each(heap_context ctx, heap_for_each_func action, void *uap) {
226 	int i;
227 
228 	if (ctx == NULL || action == NULL) {
229 		errno = EINVAL;
230 		return (-1);
231 	}
232 
233 	for (i = 1; i <= ctx->heap_size; i++)
234 		(action)(ctx->heap[i], uap);
235 	return (0);
236 }
237 
238 /*! \file */
239