xref: /linux/fs/bcachefs/eytzinger.h (revision 1c6fdbd8f2465ddfb73a01ec620cbf3d14044e1a)
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