1*1c6fdbd8SKent Overstreet /* SPDX-License-Identifier: GPL-2.0 */ 2*1c6fdbd8SKent Overstreet #ifndef _EYTZINGER_H 3*1c6fdbd8SKent Overstreet #define _EYTZINGER_H 4*1c6fdbd8SKent Overstreet 5*1c6fdbd8SKent Overstreet #include <linux/bitops.h> 6*1c6fdbd8SKent Overstreet #include <linux/log2.h> 7*1c6fdbd8SKent Overstreet 8*1c6fdbd8SKent Overstreet #include "util.h" 9*1c6fdbd8SKent Overstreet 10*1c6fdbd8SKent Overstreet /* 11*1c6fdbd8SKent Overstreet * Traversal for trees in eytzinger layout - a full binary tree layed out in an 12*1c6fdbd8SKent Overstreet * array 13*1c6fdbd8SKent Overstreet */ 14*1c6fdbd8SKent Overstreet 15*1c6fdbd8SKent Overstreet /* 16*1c6fdbd8SKent Overstreet * One based indexing version: 17*1c6fdbd8SKent Overstreet * 18*1c6fdbd8SKent Overstreet * With one based indexing each level of the tree starts at a power of two - 19*1c6fdbd8SKent Overstreet * good for cacheline alignment: 20*1c6fdbd8SKent Overstreet * 21*1c6fdbd8SKent Overstreet * Size parameter is treated as if we were using 0 based indexing, however: 22*1c6fdbd8SKent Overstreet * valid nodes, and inorder indices, are in the range [1..size) - that is, there 23*1c6fdbd8SKent Overstreet * are actually size - 1 elements 24*1c6fdbd8SKent Overstreet */ 25*1c6fdbd8SKent Overstreet 26*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_child(unsigned i, unsigned child) 27*1c6fdbd8SKent Overstreet { 28*1c6fdbd8SKent Overstreet EBUG_ON(child > 1); 29*1c6fdbd8SKent Overstreet 30*1c6fdbd8SKent Overstreet return (i << 1) + child; 31*1c6fdbd8SKent Overstreet } 32*1c6fdbd8SKent Overstreet 33*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_left_child(unsigned i) 34*1c6fdbd8SKent Overstreet { 35*1c6fdbd8SKent Overstreet return eytzinger1_child(i, 0); 36*1c6fdbd8SKent Overstreet } 37*1c6fdbd8SKent Overstreet 38*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_right_child(unsigned i) 39*1c6fdbd8SKent Overstreet { 40*1c6fdbd8SKent Overstreet return eytzinger1_child(i, 1); 41*1c6fdbd8SKent Overstreet } 42*1c6fdbd8SKent Overstreet 43*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_first(unsigned size) 44*1c6fdbd8SKent Overstreet { 45*1c6fdbd8SKent Overstreet return rounddown_pow_of_two(size - 1); 46*1c6fdbd8SKent Overstreet } 47*1c6fdbd8SKent Overstreet 48*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_last(unsigned size) 49*1c6fdbd8SKent Overstreet { 50*1c6fdbd8SKent Overstreet return rounddown_pow_of_two(size) - 1; 51*1c6fdbd8SKent Overstreet } 52*1c6fdbd8SKent Overstreet 53*1c6fdbd8SKent Overstreet /* 54*1c6fdbd8SKent Overstreet * eytzinger1_next() and eytzinger1_prev() have the nice properties that 55*1c6fdbd8SKent Overstreet * 56*1c6fdbd8SKent Overstreet * eytzinger1_next(0) == eytzinger1_first()) 57*1c6fdbd8SKent Overstreet * eytzinger1_prev(0) == eytzinger1_last()) 58*1c6fdbd8SKent Overstreet * 59*1c6fdbd8SKent Overstreet * eytzinger1_prev(eytzinger1_first()) == 0 60*1c6fdbd8SKent Overstreet * eytzinger1_next(eytzinger1_last()) == 0 61*1c6fdbd8SKent Overstreet */ 62*1c6fdbd8SKent Overstreet 63*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_next(unsigned i, unsigned size) 64*1c6fdbd8SKent Overstreet { 65*1c6fdbd8SKent Overstreet EBUG_ON(i >= size); 66*1c6fdbd8SKent Overstreet 67*1c6fdbd8SKent Overstreet if (eytzinger1_right_child(i) < size) { 68*1c6fdbd8SKent Overstreet i = eytzinger1_right_child(i); 69*1c6fdbd8SKent Overstreet 70*1c6fdbd8SKent Overstreet i <<= __fls(size) - __fls(i); 71*1c6fdbd8SKent Overstreet i >>= i >= size; 72*1c6fdbd8SKent Overstreet } else { 73*1c6fdbd8SKent Overstreet i >>= ffz(i) + 1; 74*1c6fdbd8SKent Overstreet } 75*1c6fdbd8SKent Overstreet 76*1c6fdbd8SKent Overstreet return i; 77*1c6fdbd8SKent Overstreet } 78*1c6fdbd8SKent Overstreet 79*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_prev(unsigned i, unsigned size) 80*1c6fdbd8SKent Overstreet { 81*1c6fdbd8SKent Overstreet EBUG_ON(i >= size); 82*1c6fdbd8SKent Overstreet 83*1c6fdbd8SKent Overstreet if (eytzinger1_left_child(i) < size) { 84*1c6fdbd8SKent Overstreet i = eytzinger1_left_child(i) + 1; 85*1c6fdbd8SKent Overstreet 86*1c6fdbd8SKent Overstreet i <<= __fls(size) - __fls(i); 87*1c6fdbd8SKent Overstreet i -= 1; 88*1c6fdbd8SKent Overstreet i >>= i >= size; 89*1c6fdbd8SKent Overstreet } else { 90*1c6fdbd8SKent Overstreet i >>= __ffs(i) + 1; 91*1c6fdbd8SKent Overstreet } 92*1c6fdbd8SKent Overstreet 93*1c6fdbd8SKent Overstreet return i; 94*1c6fdbd8SKent Overstreet } 95*1c6fdbd8SKent Overstreet 96*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_extra(unsigned size) 97*1c6fdbd8SKent Overstreet { 98*1c6fdbd8SKent Overstreet return (size - rounddown_pow_of_two(size - 1)) << 1; 99*1c6fdbd8SKent Overstreet } 100*1c6fdbd8SKent Overstreet 101*1c6fdbd8SKent Overstreet static inline unsigned __eytzinger1_to_inorder(unsigned i, unsigned size, 102*1c6fdbd8SKent Overstreet unsigned extra) 103*1c6fdbd8SKent Overstreet { 104*1c6fdbd8SKent Overstreet unsigned b = __fls(i); 105*1c6fdbd8SKent Overstreet unsigned shift = __fls(size - 1) - b; 106*1c6fdbd8SKent Overstreet int s; 107*1c6fdbd8SKent Overstreet 108*1c6fdbd8SKent Overstreet EBUG_ON(!i || i >= size); 109*1c6fdbd8SKent Overstreet 110*1c6fdbd8SKent Overstreet i ^= 1U << b; 111*1c6fdbd8SKent Overstreet i <<= 1; 112*1c6fdbd8SKent Overstreet i |= 1; 113*1c6fdbd8SKent Overstreet i <<= shift; 114*1c6fdbd8SKent Overstreet 115*1c6fdbd8SKent Overstreet /* 116*1c6fdbd8SKent Overstreet * sign bit trick: 117*1c6fdbd8SKent Overstreet * 118*1c6fdbd8SKent Overstreet * if (i > extra) 119*1c6fdbd8SKent Overstreet * i -= (i - extra) >> 1; 120*1c6fdbd8SKent Overstreet */ 121*1c6fdbd8SKent Overstreet s = extra - i; 122*1c6fdbd8SKent Overstreet i += (s >> 1) & (s >> 31); 123*1c6fdbd8SKent Overstreet 124*1c6fdbd8SKent Overstreet return i; 125*1c6fdbd8SKent Overstreet } 126*1c6fdbd8SKent Overstreet 127*1c6fdbd8SKent Overstreet static inline unsigned __inorder_to_eytzinger1(unsigned i, unsigned size, 128*1c6fdbd8SKent Overstreet unsigned extra) 129*1c6fdbd8SKent Overstreet { 130*1c6fdbd8SKent Overstreet unsigned shift; 131*1c6fdbd8SKent Overstreet int s; 132*1c6fdbd8SKent Overstreet 133*1c6fdbd8SKent Overstreet EBUG_ON(!i || i >= size); 134*1c6fdbd8SKent Overstreet 135*1c6fdbd8SKent Overstreet /* 136*1c6fdbd8SKent Overstreet * sign bit trick: 137*1c6fdbd8SKent Overstreet * 138*1c6fdbd8SKent Overstreet * if (i > extra) 139*1c6fdbd8SKent Overstreet * i += i - extra; 140*1c6fdbd8SKent Overstreet */ 141*1c6fdbd8SKent Overstreet s = extra - i; 142*1c6fdbd8SKent Overstreet i -= s & (s >> 31); 143*1c6fdbd8SKent Overstreet 144*1c6fdbd8SKent Overstreet shift = __ffs(i); 145*1c6fdbd8SKent Overstreet 146*1c6fdbd8SKent Overstreet i >>= shift + 1; 147*1c6fdbd8SKent Overstreet i |= 1U << (__fls(size - 1) - shift); 148*1c6fdbd8SKent Overstreet 149*1c6fdbd8SKent Overstreet return i; 150*1c6fdbd8SKent Overstreet } 151*1c6fdbd8SKent Overstreet 152*1c6fdbd8SKent Overstreet static inline unsigned eytzinger1_to_inorder(unsigned i, unsigned size) 153*1c6fdbd8SKent Overstreet { 154*1c6fdbd8SKent Overstreet return __eytzinger1_to_inorder(i, size, eytzinger1_extra(size)); 155*1c6fdbd8SKent Overstreet } 156*1c6fdbd8SKent Overstreet 157*1c6fdbd8SKent Overstreet static inline unsigned inorder_to_eytzinger1(unsigned i, unsigned size) 158*1c6fdbd8SKent Overstreet { 159*1c6fdbd8SKent Overstreet return __inorder_to_eytzinger1(i, size, eytzinger1_extra(size)); 160*1c6fdbd8SKent Overstreet } 161*1c6fdbd8SKent Overstreet 162*1c6fdbd8SKent Overstreet #define eytzinger1_for_each(_i, _size) \ 163*1c6fdbd8SKent Overstreet for ((_i) = eytzinger1_first((_size)); \ 164*1c6fdbd8SKent Overstreet (_i) != 0; \ 165*1c6fdbd8SKent Overstreet (_i) = eytzinger1_next((_i), (_size))) 166*1c6fdbd8SKent Overstreet 167*1c6fdbd8SKent Overstreet /* Zero based indexing version: */ 168*1c6fdbd8SKent Overstreet 169*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_child(unsigned i, unsigned child) 170*1c6fdbd8SKent Overstreet { 171*1c6fdbd8SKent Overstreet EBUG_ON(child > 1); 172*1c6fdbd8SKent Overstreet 173*1c6fdbd8SKent Overstreet return (i << 1) + 1 + child; 174*1c6fdbd8SKent Overstreet } 175*1c6fdbd8SKent Overstreet 176*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_left_child(unsigned i) 177*1c6fdbd8SKent Overstreet { 178*1c6fdbd8SKent Overstreet return eytzinger0_child(i, 0); 179*1c6fdbd8SKent Overstreet } 180*1c6fdbd8SKent Overstreet 181*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_right_child(unsigned i) 182*1c6fdbd8SKent Overstreet { 183*1c6fdbd8SKent Overstreet return eytzinger0_child(i, 1); 184*1c6fdbd8SKent Overstreet } 185*1c6fdbd8SKent Overstreet 186*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_first(unsigned size) 187*1c6fdbd8SKent Overstreet { 188*1c6fdbd8SKent Overstreet return eytzinger1_first(size + 1) - 1; 189*1c6fdbd8SKent Overstreet } 190*1c6fdbd8SKent Overstreet 191*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_last(unsigned size) 192*1c6fdbd8SKent Overstreet { 193*1c6fdbd8SKent Overstreet return eytzinger1_last(size + 1) - 1; 194*1c6fdbd8SKent Overstreet } 195*1c6fdbd8SKent Overstreet 196*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_next(unsigned i, unsigned size) 197*1c6fdbd8SKent Overstreet { 198*1c6fdbd8SKent Overstreet return eytzinger1_next(i + 1, size + 1) - 1; 199*1c6fdbd8SKent Overstreet } 200*1c6fdbd8SKent Overstreet 201*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_prev(unsigned i, unsigned size) 202*1c6fdbd8SKent Overstreet { 203*1c6fdbd8SKent Overstreet return eytzinger1_prev(i + 1, size + 1) - 1; 204*1c6fdbd8SKent Overstreet } 205*1c6fdbd8SKent Overstreet 206*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_extra(unsigned size) 207*1c6fdbd8SKent Overstreet { 208*1c6fdbd8SKent Overstreet return eytzinger1_extra(size + 1); 209*1c6fdbd8SKent Overstreet } 210*1c6fdbd8SKent Overstreet 211*1c6fdbd8SKent Overstreet static inline unsigned __eytzinger0_to_inorder(unsigned i, unsigned size, 212*1c6fdbd8SKent Overstreet unsigned extra) 213*1c6fdbd8SKent Overstreet { 214*1c6fdbd8SKent Overstreet return __eytzinger1_to_inorder(i + 1, size + 1, extra) - 1; 215*1c6fdbd8SKent Overstreet } 216*1c6fdbd8SKent Overstreet 217*1c6fdbd8SKent Overstreet static inline unsigned __inorder_to_eytzinger0(unsigned i, unsigned size, 218*1c6fdbd8SKent Overstreet unsigned extra) 219*1c6fdbd8SKent Overstreet { 220*1c6fdbd8SKent Overstreet return __inorder_to_eytzinger1(i + 1, size + 1, extra) - 1; 221*1c6fdbd8SKent Overstreet } 222*1c6fdbd8SKent Overstreet 223*1c6fdbd8SKent Overstreet static inline unsigned eytzinger0_to_inorder(unsigned i, unsigned size) 224*1c6fdbd8SKent Overstreet { 225*1c6fdbd8SKent Overstreet return __eytzinger0_to_inorder(i, size, eytzinger0_extra(size)); 226*1c6fdbd8SKent Overstreet } 227*1c6fdbd8SKent Overstreet 228*1c6fdbd8SKent Overstreet static inline unsigned inorder_to_eytzinger0(unsigned i, unsigned size) 229*1c6fdbd8SKent Overstreet { 230*1c6fdbd8SKent Overstreet return __inorder_to_eytzinger0(i, size, eytzinger0_extra(size)); 231*1c6fdbd8SKent Overstreet } 232*1c6fdbd8SKent Overstreet 233*1c6fdbd8SKent Overstreet #define eytzinger0_for_each(_i, _size) \ 234*1c6fdbd8SKent Overstreet for ((_i) = eytzinger0_first((_size)); \ 235*1c6fdbd8SKent Overstreet (_i) != -1; \ 236*1c6fdbd8SKent Overstreet (_i) = eytzinger0_next((_i), (_size))) 237*1c6fdbd8SKent Overstreet 238*1c6fdbd8SKent Overstreet typedef int (*eytzinger_cmp_fn)(const void *l, const void *r, size_t size); 239*1c6fdbd8SKent Overstreet 240*1c6fdbd8SKent Overstreet /* return greatest node <= @search, or -1 if not found */ 241*1c6fdbd8SKent Overstreet static inline ssize_t eytzinger0_find_le(void *base, size_t nr, size_t size, 242*1c6fdbd8SKent Overstreet eytzinger_cmp_fn cmp, const void *search) 243*1c6fdbd8SKent Overstreet { 244*1c6fdbd8SKent Overstreet unsigned i, n = 0; 245*1c6fdbd8SKent Overstreet 246*1c6fdbd8SKent Overstreet if (!nr) 247*1c6fdbd8SKent Overstreet return -1; 248*1c6fdbd8SKent Overstreet 249*1c6fdbd8SKent Overstreet do { 250*1c6fdbd8SKent Overstreet i = n; 251*1c6fdbd8SKent Overstreet n = eytzinger0_child(i, cmp(search, base + i * size, size) >= 0); 252*1c6fdbd8SKent Overstreet } while (n < nr); 253*1c6fdbd8SKent Overstreet 254*1c6fdbd8SKent Overstreet if (n & 1) { 255*1c6fdbd8SKent Overstreet /* @i was greater than @search, return previous node: */ 256*1c6fdbd8SKent Overstreet 257*1c6fdbd8SKent Overstreet if (i == eytzinger0_first(nr)) 258*1c6fdbd8SKent Overstreet return -1; 259*1c6fdbd8SKent Overstreet 260*1c6fdbd8SKent Overstreet return eytzinger0_prev(i, nr); 261*1c6fdbd8SKent Overstreet } else { 262*1c6fdbd8SKent Overstreet return i; 263*1c6fdbd8SKent Overstreet } 264*1c6fdbd8SKent Overstreet } 265*1c6fdbd8SKent Overstreet 266*1c6fdbd8SKent Overstreet static inline size_t eytzinger0_find(void *base, size_t nr, size_t size, 267*1c6fdbd8SKent Overstreet eytzinger_cmp_fn cmp, const void *search) 268*1c6fdbd8SKent Overstreet { 269*1c6fdbd8SKent Overstreet size_t i = 0; 270*1c6fdbd8SKent Overstreet int res; 271*1c6fdbd8SKent Overstreet 272*1c6fdbd8SKent Overstreet while (i < nr && 273*1c6fdbd8SKent Overstreet (res = cmp(search, base + i * size, size))) 274*1c6fdbd8SKent Overstreet i = eytzinger0_child(i, res > 0); 275*1c6fdbd8SKent Overstreet 276*1c6fdbd8SKent Overstreet return i; 277*1c6fdbd8SKent Overstreet } 278*1c6fdbd8SKent Overstreet 279*1c6fdbd8SKent Overstreet void eytzinger0_sort(void *, size_t, size_t, 280*1c6fdbd8SKent Overstreet int (*cmp_func)(const void *, const void *, size_t), 281*1c6fdbd8SKent Overstreet void (*swap_func)(void *, void *, size_t)); 282*1c6fdbd8SKent Overstreet 283*1c6fdbd8SKent Overstreet #endif /* _EYTZINGER_H */ 284