| /* |
| * Simple insertion-only static-sized priority heap containing |
| * pointers, based on CLR, chapter 7 |
| */ |
| |
| #include <linux/slab.h> |
| #include <linux/prio_heap.h> |
| |
| int heap_init(struct ptr_heap *heap, size_t size, gfp_t gfp_mask, |
| int (*gt)(void *, void *)) |
| { |
| heap->ptrs = kmalloc(size, gfp_mask); |
| if (!heap->ptrs) |
| return -ENOMEM; |
| heap->size = 0; |
| heap->max = size / sizeof(void *); |
| heap->gt = gt; |
| return 0; |
| } |
| |
| void heap_free(struct ptr_heap *heap) |
| { |
| kfree(heap->ptrs); |
| } |
| |
| void *heap_insert(struct ptr_heap *heap, void *p) |
| { |
| void *res; |
| void **ptrs = heap->ptrs; |
| int pos; |
| |
| if (heap->size < heap->max) { |
| /* Heap insertion */ |
| pos = heap->size++; |
| while (pos > 0 && heap->gt(p, ptrs[(pos-1)/2])) { |
| ptrs[pos] = ptrs[(pos-1)/2]; |
| pos = (pos-1)/2; |
| } |
| ptrs[pos] = p; |
| return NULL; |
| } |
| |
| /* The heap is full, so something will have to be dropped */ |
| |
| /* If the new pointer is greater than the current max, drop it */ |
| if (heap->gt(p, ptrs[0])) |
| return p; |
| |
| /* Replace the current max and heapify */ |
| res = ptrs[0]; |
| ptrs[0] = p; |
| pos = 0; |
| |
| while (1) { |
| int left = 2 * pos + 1; |
| int right = 2 * pos + 2; |
| int largest = pos; |
| if (left < heap->size && heap->gt(ptrs[left], p)) |
| largest = left; |
| if (right < heap->size && heap->gt(ptrs[right], ptrs[largest])) |
| largest = right; |
| if (largest == pos) |
| break; |
| /* Push p down the heap one level and bump one up */ |
| ptrs[pos] = ptrs[largest]; |
| ptrs[largest] = p; |
| pos = largest; |
| } |
| return res; |
| } |