]> jfr.im git - irc/evilnet/x3.git/blame - src/heap.c
Minor typo in previous commit where returning 0 when it should have been 1 from opser...
[irc/evilnet/x3.git] / src / heap.c
CommitLineData
d76ed9a9 1/* heap.c - Abstract heap type
2 * Copyright 2000-2002 srvx Development Team
3 *
1136f709 4 * This file is part of srvx.
d76ed9a9 5 *
1136f709 6 * srvx is free software; you can redistribute it and/or modify
d76ed9a9 7 * it under the terms of the GNU General Public License as published by
be2c97a5 8 * the Free Software Foundation; either version 3 of the License, or
d76ed9a9 9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21#include "common.h"
22#include "heap.h"
23
24/* Possible optimizations:
25 *
26 * Use another type of heap (rather than binary) if our heaps are big enough.
27 *
28 * Coalesce multiple entries with the same key into the same chunk, and have
29 * a new API function to return all of the entries at the top of the heap.
30 */
31
32struct heap {
33 comparator_f comparator;
34 void **data;
35 unsigned int data_used, data_alloc;
36};
37
38/*
39 * Allocate a new heap.
40 */
41heap_t
42heap_new(comparator_f comparator)
43{
44 heap_t heap = malloc(sizeof(struct heap));
45 heap->comparator = comparator;
46 heap->data_used = 0;
47 heap->data_alloc = 8;
48 heap->data = malloc(2*heap->data_alloc*sizeof(void*));
49 return heap;
50}
51
52/*
53 * Move the element at "index" in the heap as far up the heap as is
54 * proper (i.e., as long as its parent node is less than or equal to
55 * its value).
56 */
57static void
1136f709 58heap_heapify_up(heap_t heap, unsigned int idx)
d76ed9a9 59{
60 int res;
61 unsigned int parent;
62 void *last_key, *last_data;
1136f709 63
64 last_key = heap->data[idx*2];
65 last_data = heap->data[idx*2+1];
66 while (idx > 0) {
67 parent = (idx - 1) >> 1;
68 res = heap->comparator(last_key, heap->data[parent*2]);
69 if (res > 0) break;
70 heap->data[idx*2] = heap->data[parent*2];
71 heap->data[idx*2+1] = heap->data[parent*2+1];
72 idx = parent;
d76ed9a9 73 }
1136f709 74 heap->data[idx*2] = last_key;
75 heap->data[idx*2+1] = last_data;
d76ed9a9 76}
77
78/*
79 * Insert a key/data pair into the heap.
80 */
81void
82heap_insert(heap_t heap, void *key, void *data)
83{
84 if (heap->data_used == heap->data_alloc) {
1136f709 85 heap->data_alloc *= 2;
86 heap->data = realloc(heap->data, 2*heap->data_alloc*sizeof(void*));
d76ed9a9 87 }
88 heap->data[heap->data_used*2] = key;
89 heap->data[heap->data_used*2+1] = data;
90 heap_heapify_up(heap, heap->data_used++);
91}
92
93/*
94 * Return what's on top of the heap.
95 * If the heap is empty, put NULL into *key and *data.
96 * (Either key or data may be NULL, in which case the relevant
97 * data will not be returned to the caller.)
98 */
99void
100heap_peek(heap_t heap, void **key, void **data)
101{
102 if (key) *key = heap->data_used ? heap->data[0] : NULL;
103 if (data) *data = heap->data_used ? heap->data[1] : NULL;
104}
105
106/*
107 * Push the element at "pos" down the heap as far as it will go.
108 */
109static void
110heap_heapify_down(heap_t heap, int pos)
111{
112 int res;
113 unsigned int child;
114 void *last_key, *last_data;
115 last_key = heap->data[pos*2];
116 last_data = heap->data[pos*2+1];
117 /* start at left child */
118 while ((child=pos*2+1) < heap->data_used) {
1136f709 119 /* use right child if it exists and is smaller */
120 if (child+1 < heap->data_used) {
121 res = heap->comparator(heap->data[(child+1)*2], heap->data[child*2]);
122 if (res < 0) child = child+1;
123 }
124 res = heap->comparator(last_key, heap->data[child*2]);
125 if (res <= 0) break;
126 heap->data[pos*2] = heap->data[child*2];
127 heap->data[pos*2+1] = heap->data[child*2+1];
128 pos = child;
d76ed9a9 129 }
130 heap->data[pos*2] = last_key;
131 heap->data[pos*2+1] = last_data;
132}
133
134/*
1136f709 135 * Remove the element at "idx" from the heap (preserving the heap ordering).
d76ed9a9 136 */
137static void
1136f709 138heap_remove(heap_t heap, unsigned int idx)
d76ed9a9 139{
140 /* sanity check */
1136f709 141 if (heap->data_used <= idx) return;
142 /* swap idx with last element */
d76ed9a9 143 heap->data_used--;
1136f709 144 heap->data[idx*2] = heap->data[heap->data_used*2];
145 heap->data[idx*2+1] = heap->data[heap->data_used*2+1];
146 /* heapify down if idx has children */
147 if (heap->data_used >= 2*idx+1) heap_heapify_down(heap, idx);
148 if ((idx > 0) && (idx < heap->data_used)) heap_heapify_up(heap, idx);
d76ed9a9 149}
150
151/*
152 * Pop the topmost element from the heap (preserving the heap ordering).
153 */
154void
155heap_pop(heap_t heap)
156{
157 heap_remove(heap, 0);
158}
159
160/*
161 * Remove all elements from the heap if pred(key, data, extra) returns
162 * non-zero on the element's key/data pair. Can be abused to iterate
163 * over the entire heap, by always returning 0 from pred.
164 *
165 * Returns non-zero if the predicate causes the top of the heap to be
166 * removed.
167 */
168int
169heap_remove_pred(heap_t heap, int (*pred)(void *key, void *data, void *extra), void *extra)
170{
171 unsigned int pos, rem_first;
172
173 if (heap->data_used == 0) return 0;
174 if (pred(heap->data[0], heap->data[1], extra)) {
175 heap_remove(heap, 0);
176 rem_first = 1;
177 pos = 0;
178 } else {
179 rem_first = 0;
180 pos = 1;
181 }
182 while (pos < heap->data_used) {
1136f709 183 if (pred(heap->data[pos*2], heap->data[pos*2+1], extra)) {
d76ed9a9 184 heap_remove(heap, pos);
185 pos = 0;
186 } else {
187 pos++;
188 }
189 }
190 return rem_first;
191}
192
193/*
194 * Remove all entries from a heap.
195 */
196void
197heap_delete(heap_t heap)
198{
199 free(heap->data);
200 free(heap);
201}
202
203/*
204 * Return number of entries in the heap.
205 */
206unsigned int
207heap_size(heap_t heap)
208{
209 return heap->data_used;
210}
211
212/* prepackaged comparators */
213int
1136f709 214ulong_comparator(const void *a, const void *b)
d76ed9a9 215{
1136f709 216 return (unsigned long)a-(unsigned long)b;
d76ed9a9 217}