1 #include <freeradius-devel/ident.h>
4 #include <freeradius-devel/libradius.h>
5 #include <freeradius-devel/heap.h>
8 * A heap entry is made of a pointer to the object, which
9 * contains the key. The heap itself is an array of pointers.
11 * Heaps normally support only ordered insert, and extraction
12 * of the minimum element. The heap entry can contain an "int"
13 * field that holds the entries position in the heap. The offset
14 * of the field is held inside of the heap structure.
26 * First node in a heap is element 0. Children of i are 2i+1 and
27 * 2i+2. These macros wrap the logic, so the code is more
30 #define HEAP_PARENT(x) ( ( (x) - 1 ) / 2 )
31 #define HEAP_LEFT(x) ( 2*(x) + 1 )
32 #define HEAP_RIGHT(x) ( 2*(x) + 2 )
33 #define HEAP_SWAP(a, b) { void *_tmp = a; a = b; b = _tmp; }
35 static int fr_heap_bubble(fr_heap_t *hp, int child);
37 void fr_heap_delete(fr_heap_t *hp)
45 fr_heap_t *fr_heap_create(fr_heap_cmp_t cmp, size_t offset)
49 if (!cmp) return NULL;
51 fh = malloc(sizeof(*fh));
54 memset(fh, 0, sizeof(*fh));
57 fh->p = malloc(sizeof(*(fh->p)) * fh->size);
70 * Insert element in heap. Normally, p != NULL, we insert p in a
71 * new position and bubble up. If p == NULL, then the element is
72 * already in place, and key is the position where to start the
75 * Returns 1 on failure (cannot allocate new heap entry)
77 * If offset > 0 the position (index, int) of the element in the
78 * heap is also stored in the element itself at the given offset
81 #define SET_OFFSET(heap, node) \
83 *((int *)(((uint8_t *)heap->p[node]) + heap->offset)) = node
86 * RESET_OFFSET is used for sanity checks. It sets offset to an
89 #define RESET_OFFSET(heap, node) \
91 *((int *)(((uint8_t *)heap->p[node]) + heap->offset)) = -1
93 int fr_heap_insert(fr_heap_t *hp, void *data)
95 int child = hp->num_elements;
98 * Heap is full. Double it's size.
100 if (child == hp->size) {
103 p = malloc(2 * hp->size * sizeof(*p));
106 memcpy(p, hp->p, sizeof(*p) * hp->size);
115 return fr_heap_bubble(hp, child);
119 static int fr_heap_bubble(fr_heap_t *hp, int child)
122 * Bubble up the element.
125 int parent = HEAP_PARENT(child);
128 * Parent is smaller than the child. We're done.
130 if (hp->cmp(hp->p[parent], hp->p[child]) < 0) break;
133 * Child is smaller than the parent, repeat.
135 HEAP_SWAP(hp->p[child], hp->p[parent]);
136 SET_OFFSET(hp, child);
139 SET_OFFSET(hp, child);
146 * Remove the top element, or object.
148 int fr_heap_extract(fr_heap_t *hp, void *data)
153 if (!hp || (hp->num_elements == 0)) return 0;
155 max = hp->num_elements - 1;
158 * Extract element. Default is the first one.
163 } else { /* extract from the middle */
164 if (!hp->offset) return 0;
166 parent = *((int *)(((uint8_t *)data) + hp->offset));
171 if (parent < 0 || parent >= hp->num_elements) return 0;
174 RESET_OFFSET(hp, parent);
175 child = HEAP_LEFT(parent);
176 while (child <= max) {
178 * Maybe take the right child.
180 if ((child != max) &&
181 (hp->cmp(hp->p[child + 1], hp->p[child]) < 0)) {
184 hp->p[parent] = hp->p[child];
185 SET_OFFSET(hp, parent);
187 child = HEAP_LEFT(child);
192 * We didn't end up at the last element in the heap.
193 * This element has to be re-inserted.
197 * Fill hole with last entry and bubble up,
198 * reusing the insert code
200 hp->p[parent] = hp->p[max];
201 return fr_heap_bubble(hp, parent);
208 void *fr_heap_peek(fr_heap_t *hp)
210 if (!hp || (hp->num_elements == 0)) return NULL;
213 * If this is NULL, we have a problem.
218 int fr_heap_num_elements(fr_heap_t *hp)
222 return hp->num_elements;
228 * cc -g -DTESTING -I .. heap.c -o heap
237 static int heap_cmp(const void *a, const void *b)
239 return *(int *)a - *(int *) b;
244 int main(int argc, char **arg)
249 hp = fr_heap_create(heap_cmp, 0);
251 fprintf(stderr, "Failed creating heap!\n");
255 for (i = 0; i < 1024; i++) {
256 array[i] = (i * 257) % 65537;
257 if (!fr_heap_insert(hp, &array[i])) {
258 fprintf(stderr, "Failed inserting %d\n", i);
263 for (i = 0; i < 1024; i++) {
264 int *p = fr_heap_peek(hp);
267 fprintf(stderr, "Failed peeking %d\n", i);
271 printf("%d\t%d\n", i, *p);
273 if (!fr_heap_extract(hp, NULL)) {
274 fprintf(stderr, "Failed extracting %d\n", i);