xref: /freebsd/sys/netpfil/ipfilter/netinet/ipf_rb.h (revision e0c4386e)
1 /*
2  * Copyright (C) 2012 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  */
7 typedef enum rbcolour_e {
8 	C_BLACK = 0,
9 	C_RED = 1
10 } rbcolour_t;
11 
12 #define	RBI_LINK(_n, _t)							\
13 	struct _n##_rb_link {						\
14 		struct _t	*left;					\
15 		struct _t	*right;					\
16 		struct _t	*parent;				\
17 		rbcolour_t	colour;					\
18 	}
19 
20 #define	RBI_HEAD(_n, _t)						\
21 struct _n##_rb_head {							\
22 	struct _t	top;						\
23 	int		count;						\
24 	int		(* compare)(struct _t *, struct _t *);		\
25 }
26 
27 #define	RBI_CODE(_n, _t, _f, _cmp)					\
28 									\
29 typedef	void	(*_n##_rb_walker_t)(_t *, void *);			\
30 									\
31 _t *	_n##_rb_delete(struct _n##_rb_head *, _t *);			\
32 void	_n##_rb_init(struct _n##_rb_head *);				\
33 void	_n##_rb_insert(struct _n##_rb_head *, _t *);			\
34 _t *	_n##_rb_search(struct _n##_rb_head *, void *);			\
35 void	_n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
36 									\
37 static void								\
38 rotate_left(struct _n##_rb_head *head, _t *node)			\
39 {									\
40 	_t *parent, *tmp1, *tmp2;					\
41 									\
42 	parent = node->_f.parent;					\
43 	tmp1 = node->_f.right;						\
44 	tmp2 = tmp1->_f.left;						\
45 	node->_f.right = tmp2;						\
46 	if (tmp2 != & _n##_rb_zero)					\
47 		tmp2->_f.parent = node;					\
48 	if (parent == & _n##_rb_zero)					\
49 		head->top._f.right = tmp1;				\
50 	else if (parent->_f.right == node)				\
51 		parent->_f.right = tmp1;				\
52 	else								\
53 		parent->_f.left = tmp1;					\
54 	tmp1->_f.left = node;						\
55 	tmp1->_f.parent = parent;					\
56 	node->_f.parent = tmp1;						\
57 }									\
58 									\
59 static void								\
60 rotate_right(struct _n##_rb_head *head, _t *node)			\
61 {									\
62 	_t *parent, *tmp1, *tmp2;					\
63 									\
64 	parent = node->_f.parent;					\
65 	tmp1 = node->_f.left;						\
66 	tmp2 = tmp1->_f.right;						\
67 	node->_f.left = tmp2;						\
68 	if (tmp2 != &_n##_rb_zero)					\
69 		tmp2->_f.parent = node;					\
70 	if (parent == &_n##_rb_zero)					\
71 		head->top._f.right = tmp1;				\
72 	else if (parent->_f.right == node)				\
73 		parent->_f.right = tmp1;				\
74 	else								\
75 		parent->_f.left = tmp1;					\
76 	tmp1->_f.right = node;						\
77 	tmp1->_f.parent = parent;					\
78 	node->_f.parent = tmp1;						\
79 }									\
80 									\
81 void									\
82 _n##_rb_insert(struct _n##_rb_head *head, _t *node)			\
83 {									\
84 	_t *n, *parent, **p, *tmp1, *gparent;				\
85 									\
86 	parent = &head->top;						\
87 	node->_f.left = &_n##_rb_zero;					\
88 	node->_f.right = &_n##_rb_zero;					\
89 	p = &head->top._f.right;					\
90 	while ((n = *p) != &_n##_rb_zero) {				\
91 		if (_cmp(node, n) < 0)					\
92 			p = &n->_f.left;				\
93 		else							\
94 			p = &n->_f.right;				\
95 		parent = n;						\
96 	}								\
97 	*p = node;							\
98 	node->_f.colour = C_RED;					\
99 	node->_f.parent = parent;					\
100 									\
101 	while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
102 		gparent = parent->_f.parent;				\
103 		if (parent == gparent->_f.left) {			\
104 			tmp1 = gparent->_f.right;			\
105 			if (tmp1->_f.colour == C_RED) {			\
106 				parent->_f.colour = C_BLACK;		\
107 				tmp1->_f.colour = C_BLACK;		\
108 				gparent->_f.colour = C_RED;		\
109 				node = gparent;				\
110 			} else {					\
111 				if (node == parent->_f.right) {		\
112 					node = parent;			\
113 					rotate_left(head, node);	\
114 					parent = node->_f.parent;	\
115 				}					\
116 				parent->_f.colour = C_BLACK;		\
117 				gparent->_f.colour = C_RED;		\
118 				rotate_right(head, gparent);		\
119 			}						\
120 		} else {						\
121 			tmp1 = gparent->_f.left;			\
122 			if (tmp1->_f.colour == C_RED) {			\
123 				parent->_f.colour = C_BLACK;		\
124 				tmp1->_f.colour = C_BLACK;		\
125 				gparent->_f.colour = C_RED;		\
126 				node = gparent;				\
127 			} else {					\
128 				if (node == parent->_f.left) {		\
129 					node = parent;			\
130 					rotate_right(head, node);	\
131 					parent = node->_f.parent;	\
132 				}					\
133 				parent->_f.colour = C_BLACK;		\
134 				gparent->_f.colour = C_RED;		\
135 				rotate_left(head, parent->_f.parent);	\
136 			}						\
137 		}							\
138 		parent = node->_f.parent;				\
139 	}								\
140 	head->top._f.right->_f.colour = C_BLACK;			\
141 	head->count++;						\
142 }									\
143 									\
144 static void								\
145 deleteblack(struct _n##_rb_head *head, _t *parent, _t *node)		\
146 {									\
147 	_t *tmp;							\
148 									\
149 	while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) &&	\
150 	       node != &head->top) {					\
151 		if (parent->_f.left == node) {				\
152 			tmp = parent->_f.right;				\
153 			if (tmp->_f.colour == C_RED) {			\
154 				tmp->_f.colour = C_BLACK;		\
155 				parent->_f.colour = C_RED;		\
156 				rotate_left(head, parent);		\
157 				tmp = parent->_f.right;			\
158 			}						\
159 			if ((tmp->_f.left == &_n##_rb_zero ||		\
160 			     tmp->_f.left->_f.colour == C_BLACK) &&	\
161 			    (tmp->_f.right == &_n##_rb_zero ||		\
162 			     tmp->_f.right->_f.colour == C_BLACK)) {	\
163 				tmp->_f.colour = C_RED;			\
164 				node = parent;				\
165 				parent = node->_f.parent;		\
166 			} else {					\
167 				if (tmp->_f.right == &_n##_rb_zero ||	\
168 				    tmp->_f.right->_f.colour == C_BLACK) {\
169 					_t *tmp2 = tmp->_f.left;	\
170 									\
171 					if (tmp2 != &_n##_rb_zero)	\
172 						tmp2->_f.colour = C_BLACK;\
173 					tmp->_f.colour = C_RED;		\
174 					rotate_right(head, tmp);	\
175 					tmp = parent->_f.right;		\
176 				}					\
177 				tmp->_f.colour = parent->_f.colour;	\
178 				parent->_f.colour = C_BLACK;		\
179 				if (tmp->_f.right != &_n##_rb_zero)	\
180 					tmp->_f.right->_f.colour = C_BLACK;\
181 				rotate_left(head, parent);		\
182 				node = head->top._f.right;		\
183 			}						\
184 		} else {						\
185 			tmp = parent->_f.left;				\
186 			if (tmp->_f.colour == C_RED) {			\
187 				tmp->_f.colour = C_BLACK;		\
188 				parent->_f.colour = C_RED;		\
189 				rotate_right(head, parent);		\
190 				tmp = parent->_f.left;			\
191 			}						\
192 			if ((tmp->_f.left == &_n##_rb_zero ||		\
193 			     tmp->_f.left->_f.colour == C_BLACK) &&	\
194 			    (tmp->_f.right == &_n##_rb_zero ||		\
195 			     tmp->_f.right->_f.colour == C_BLACK)) {	\
196 				tmp->_f.colour = C_RED;			\
197 				node = parent;				\
198 				parent = node->_f.parent;		\
199 			} else {					\
200 				if (tmp->_f.left == &_n##_rb_zero ||	\
201 				    tmp->_f.left->_f.colour == C_BLACK) {\
202 					_t *tmp2 = tmp->_f.right;	\
203 									\
204 					if (tmp2 != &_n##_rb_zero)	\
205 						tmp2->_f.colour = C_BLACK;\
206 					tmp->_f.colour = C_RED;		\
207 					rotate_left(head, tmp);		\
208 					tmp = parent->_f.left;		\
209 				}					\
210 				tmp->_f.colour = parent->_f.colour;	\
211 				parent->_f.colour = C_BLACK;		\
212 				if (tmp->_f.left != &_n##_rb_zero)	\
213 					tmp->_f.left->_f.colour = C_BLACK;\
214 				rotate_right(head, parent);		\
215 				node = head->top._f.right;		\
216 				break;					\
217 			}						\
218 		}							\
219 	}								\
220 	if (node != &_n##_rb_zero)					\
221 		node->_f.colour = C_BLACK;				\
222 }									\
223 									\
224 _t *									\
225 _n##_rb_delete(struct _n##_rb_head *head, _t *node)			\
226 {									\
227 	_t *child, *parent, *old = node, *left;				\
228 	rbcolour_t color;						\
229 									\
230 	if (node->_f.left == &_n##_rb_zero) {				\
231 		child = node->_f.right;					\
232 	} else if (node->_f.right == &_n##_rb_zero) {			\
233 		child = node->_f.left;					\
234 	} else {							\
235 		node = node->_f.right;					\
236 		while ((left = node->_f.left) != &_n##_rb_zero)		\
237 			node = left;					\
238 		child = node->_f.right;					\
239 		parent = node->_f.parent;				\
240 		color = node->_f.colour;				\
241 		if (child != &_n##_rb_zero)				\
242 			child->_f.parent = parent;			\
243 		if (parent != &_n##_rb_zero) {				\
244 			if (parent->_f.left == node)			\
245 				parent->_f.left = child;		\
246 			else						\
247 				parent->_f.right = child;		\
248 		} else {						\
249 			head->top._f.right = child;			\
250 		}							\
251 		if (node->_f.parent == old)				\
252 			parent = node;					\
253 		*node = *old;						\
254 		if (old->_f.parent != &_n##_rb_zero) {			\
255 			if (old->_f.parent->_f.left == old)		\
256 				old->_f.parent->_f.left = node;		\
257 			else						\
258 				old->_f.parent->_f.right = node;	\
259 		} else {						\
260 			head->top._f.right = child;			\
261 		}							\
262 		old->_f.left->_f.parent = node;				\
263 		if (old->_f.right != &_n##_rb_zero)			\
264 			old->_f.right->_f.parent = node;		\
265 		if (parent != &_n##_rb_zero) {				\
266 			left = parent;					\
267 		}							\
268 		goto colour;						\
269 	}								\
270 	parent = node->_f.parent;					\
271 	color= node->_f.colour;						\
272 	if (child != &_n##_rb_zero)					\
273 		child->_f.parent = parent;				\
274 	if (parent != &_n##_rb_zero) {					\
275 		if (parent->_f.left == node)				\
276 			parent->_f.left = child;			\
277 		else							\
278 			parent->_f.right = child;			\
279 	} else {							\
280 		head->top._f.right = child;				\
281 	}								\
282 colour:									\
283 	if (color == C_BLACK)						\
284 		deleteblack(head, parent, node);			\
285 	head->count--;							\
286 	return (old);							\
287 }									\
288 									\
289 void									\
290 _n##_rb_init(struct _n##_rb_head *head)					\
291 {									\
292 	memset(head, 0, sizeof(*head));					\
293 	memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero));			\
294 	head->top._f.left = &_n##_rb_zero;				\
295 	head->top._f.right = &_n##_rb_zero;				\
296 	head->top._f.parent = &head->top;				\
297 	_n##_rb_zero._f.left = &_n##_rb_zero;				\
298 	_n##_rb_zero._f.right = &_n##_rb_zero;				\
299 	_n##_rb_zero._f.parent = &_n##_rb_zero;				\
300 }									\
301 									\
302 void									\
303 _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
304 {									\
305 	_t *prev;							\
306 	_t *next;							\
307 	_t *node = head->top._f.right;					\
308 	_t *base;							\
309 									\
310 	while (node != &_n##_rb_zero)					\
311 		node = node->_f.left;					\
312 									\
313 	for (;;) {							\
314 		base = node;						\
315 		prev = node;						\
316 		while ((node->_f.parent->_f.right == node) &&		\
317 		       (node != &_n##_rb_zero))	{			\
318 			prev = node;					\
319 			node = node->_f.parent;				\
320 		}							\
321 									\
322 		node = prev;						\
323 		for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
324 		     node = node->_f.left)				\
325 			prev = node;					\
326 		next = prev;						\
327 									\
328 		if (node != &_n##_rb_zero)				\
329 			func(node, arg);				\
330 									\
331 		node = next;						\
332 		if (node == &_n##_rb_zero)				\
333 			break;						\
334 	}								\
335 }									\
336 									\
337 _t *									\
338 _n##_rb_search(struct _n##_rb_head *head, void *key)			\
339 {									\
340 	int	match;							\
341 	_t	*node;							\
342 	node = head->top._f.right;					\
343 	while (node != &_n##_rb_zero) {					\
344 		match = _cmp(key, node);				\
345 		if (match == 0)						\
346 			break;						\
347 		if (match< 0)						\
348 			node = node->_f.left;				\
349 		else							\
350 			node = node->_f.right;				\
351 	}								\
352 	if (node == &_n##_rb_zero || match != 0)			\
353 		return (NULL);						\
354 	return (node);							\
355 }
356 
357 #define	RBI_DELETE(_n, _h, _v)		_n##_rb_delete(_h, _v)
358 #define	RBI_FIELD(_n)			struct _n##_rb_link
359 #define	RBI_INIT(_n, _h)		_n##_rb_init(_h)
360 #define	RBI_INSERT(_n, _h, _v)		_n##_rb_insert(_h, _v)
361 #define	RBI_ISEMPTY(_h)			((_h)->count == 0)
362 #define	RBI_SEARCH(_n, _h, _k)		_n##_rb_search(_h, _k)
363 #define	RBI_WALK(_n, _h, _w, _a)	_n##_rb_walktree(_h, _w, _a)
364 #define	RBI_ZERO(_n)			_n##_rb_zero
365