1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef _LINUX_MIN_HEAP_H 3#define _LINUX_MIN_HEAP_H 4 5#include <linux/bug.h> 6#include <linux/string.h> 7#include <linux/types.h> 8 9/** 10 * Data structure to hold a min-heap. 11 * @nr: Number of elements currently in the heap. 12 * @size: Maximum number of elements that can be held in current storage. 13 * @data: Pointer to the start of array holding the heap elements. 14 * @preallocated: Start of the static preallocated array holding the heap elements. 15 */ 16#define MIN_HEAP_PREALLOCATED(_type, _name, _nr) \ 17struct _name { \ 18 int nr; \ 19 int size; \ 20 _type *data; \ 21 _type preallocated[_nr]; \ 22} 23 24#define DEFINE_MIN_HEAP(_type, _name) MIN_HEAP_PREALLOCATED(_type, _name, 0) 25 26typedef DEFINE_MIN_HEAP(char, min_heap_char) min_heap_char; 27 28#define __minheap_cast(_heap) (typeof((_heap)->data[0]) *) 29#define __minheap_obj_size(_heap) sizeof((_heap)->data[0]) 30 31/** 32 * struct min_heap_callbacks - Data/functions to customise the min_heap. 33 * @less: Partial order function for this heap. 34 * @swp: Swap elements function. 35 */ 36struct min_heap_callbacks { 37 bool (*less)(const void *lhs, const void *rhs, void *args); 38 void (*swp)(void *lhs, void *rhs, void *args); 39}; 40 41/* Initialize a min-heap. */ 42static __always_inline 43void __min_heap_init(min_heap_char *heap, void *data, int size) 44{ 45 heap->nr = 0; 46 heap->size = size; 47 if (data) 48 heap->data = data; 49 else 50 heap->data = heap->preallocated; 51} 52 53#define min_heap_init(_heap, _data, _size) \ 54 __min_heap_init((min_heap_char *)_heap, _data, _size) 55 56/* Get the minimum element from the heap. */ 57static __always_inline 58void *__min_heap_peek(struct min_heap_char *heap) 59{ 60 return heap->nr ? heap->data : NULL; 61} 62 63#define min_heap_peek(_heap) \ 64 (__minheap_cast(_heap) __min_heap_peek((min_heap_char *)_heap)) 65 66/* Check if the heap is full. */ 67static __always_inline 68bool __min_heap_full(min_heap_char *heap) 69{ 70 return heap->nr == heap->size; 71} 72 73#define min_heap_full(_heap) \ 74 __min_heap_full((min_heap_char *)_heap) 75 76/* Sift the element at pos down the heap. */ 77static __always_inline 78void __min_heap_sift_down(min_heap_char *heap, int pos, size_t elem_size, 79 const struct min_heap_callbacks *func, void *args) 80{ 81 void *left, *right; 82 void *data = heap->data; 83 void *root = data + pos * elem_size; 84 int i = pos, j; 85 86 /* Find the sift-down path all the way to the leaves. */ 87 for (;;) { 88 if (i * 2 + 2 >= heap->nr) 89 break; 90 left = data + (i * 2 + 1) * elem_size; 91 right = data + (i * 2 + 2) * elem_size; 92 i = func->less(left, right, args) ? i * 2 + 1 : i * 2 + 2; 93 } 94 95 /* Special case for the last leaf with no sibling. */ 96 if (i * 2 + 2 == heap->nr) 97 i = i * 2 + 1; 98 99 /* Backtrack to the correct location. */ 100 while (i != pos && func->less(root, data + i * elem_size, args)) 101 i = (i - 1) / 2; 102 103 /* Shift the element into its correct place. */ 104 j = i; 105 while (i != pos) { 106 i = (i - 1) / 2; 107 func->swp(data + i * elem_size, data + j * elem_size, args); 108 } 109} 110 111#define min_heap_sift_down(_heap, _pos, _func, _args) \ 112 __min_heap_sift_down((min_heap_char *)_heap, _pos, __minheap_obj_size(_heap), _func, _args) 113 114/* Sift up ith element from the heap, O(log2(nr)). */ 115static __always_inline 116void __min_heap_sift_up(min_heap_char *heap, size_t elem_size, size_t idx, 117 const struct min_heap_callbacks *func, void *args) 118{ 119 void *data = heap->data; 120 size_t parent; 121 122 while (idx) { 123 parent = (idx - 1) / 2; 124 if (func->less(data + parent * elem_size, data + idx * elem_size, args)) 125 break; 126 func->swp(data + parent * elem_size, data + idx * elem_size, args); 127 idx = parent; 128 } 129} 130 131#define min_heap_sift_up(_heap, _idx, _func, _args) \ 132 __min_heap_sift_up((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, _func, _args) 133 134/* Floyd's approach to heapification that is O(nr). */ 135static __always_inline 136void __min_heapify_all(min_heap_char *heap, size_t elem_size, 137 const struct min_heap_callbacks *func, void *args) 138{ 139 int i; 140 141 for (i = heap->nr / 2 - 1; i >= 0; i--) 142 __min_heap_sift_down(heap, i, elem_size, func, args); 143} 144 145#define min_heapify_all(_heap, _func, _args) \ 146 __min_heapify_all((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args) 147 148/* Remove minimum element from the heap, O(log2(nr)). */ 149static __always_inline 150bool __min_heap_pop(min_heap_char *heap, size_t elem_size, 151 const struct min_heap_callbacks *func, void *args) 152{ 153 void *data = heap->data; 154 155 if (WARN_ONCE(heap->nr <= 0, "Popping an empty heap")) 156 return false; 157 158 /* Place last element at the root (position 0) and then sift down. */ 159 heap->nr--; 160 memcpy(data, data + (heap->nr * elem_size), elem_size); 161 __min_heap_sift_down(heap, 0, elem_size, func, args); 162 163 return true; 164} 165 166#define min_heap_pop(_heap, _func, _args) \ 167 __min_heap_pop((min_heap_char *)_heap, __minheap_obj_size(_heap), _func, _args) 168 169/* 170 * Remove the minimum element and then push the given element. The 171 * implementation performs 1 sift (O(log2(nr))) and is therefore more 172 * efficient than a pop followed by a push that does 2. 173 */ 174static __always_inline 175void __min_heap_pop_push(min_heap_char *heap, 176 const void *element, size_t elem_size, 177 const struct min_heap_callbacks *func, 178 void *args) 179{ 180 memcpy(heap->data, element, elem_size); 181 __min_heap_sift_down(heap, 0, elem_size, func, args); 182} 183 184#define min_heap_pop_push(_heap, _element, _func, _args) \ 185 __min_heap_pop_push((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), _func, _args) 186 187/* Push an element on to the heap, O(log2(nr)). */ 188static __always_inline 189bool __min_heap_push(min_heap_char *heap, const void *element, size_t elem_size, 190 const struct min_heap_callbacks *func, void *args) 191{ 192 void *data = heap->data; 193 int pos; 194 195 if (WARN_ONCE(heap->nr >= heap->size, "Pushing on a full heap")) 196 return false; 197 198 /* Place at the end of data. */ 199 pos = heap->nr; 200 memcpy(data + (pos * elem_size), element, elem_size); 201 heap->nr++; 202 203 /* Sift child at pos up. */ 204 __min_heap_sift_up(heap, elem_size, pos, func, args); 205 206 return true; 207} 208 209#define min_heap_push(_heap, _element, _func, _args) \ 210 __min_heap_push((min_heap_char *)_heap, _element, __minheap_obj_size(_heap), _func, _args) 211 212/* Remove ith element from the heap, O(log2(nr)). */ 213static __always_inline 214bool __min_heap_del(min_heap_char *heap, size_t elem_size, size_t idx, 215 const struct min_heap_callbacks *func, void *args) 216{ 217 void *data = heap->data; 218 219 if (WARN_ONCE(heap->nr <= 0, "Popping an empty heap")) 220 return false; 221 222 /* Place last element at the root (position 0) and then sift down. */ 223 heap->nr--; 224 if (idx == heap->nr) 225 return true; 226 func->swp(data + (idx * elem_size), data + (heap->nr * elem_size), args); 227 __min_heap_sift_up(heap, elem_size, idx, func, args); 228 __min_heap_sift_down(heap, idx, elem_size, func, args); 229 230 return true; 231} 232 233#define min_heap_del(_heap, _idx, _func, _args) \ 234 __min_heap_del((min_heap_char *)_heap, __minheap_obj_size(_heap), _idx, _func, _args) 235 236#endif /* _LINUX_MIN_HEAP_H */