ipf_rb.h revision 1.4 1 /* $NetBSD: ipf_rb.h,v 1.4 2012/12/20 21:42:28 christos Exp $ */
2
3 /*
4 * Copyright (C) 2012 by Darren Reed.
5 *
6 * See the IPFILTER.LICENCE file for details on licencing.
7 *
8 */
9
10 /*
11 * If the OS has a red-black tree implementation, use it.
12 */
13 #ifdef HAVE_RBTREE
14
15 #include <sys/rbtree.h>
16
17 # define RBI_LINK(_n, _t)
18 # define RBI_FIELD(_n) rb_node_t
19 # define RBI_HEAD(_n, _t) rb_tree_t
20
21 /* Define adapter code between the ipf-specific and the system rb impls. */
22 # define RBI_CODE(_n, _t, _f, _cmp) \
23 signed int _n##_compare_nodes(void *ctx, const void *n1, const void *n2);\
24 signed int _n##_compare_key(void *ctx, const void *n1, const void *key);\
25 typedef void (*_n##_rb_walker_t)(_t *, void *); \
26 void _n##_rb_walktree(rb_tree_t *, _n##_rb_walker_t, void *); \
27 \
28 static const rb_tree_ops_t _n##_tree_ops = { \
29 .rbto_compare_nodes = _n##_compare_nodes, \
30 .rbto_compare_key = _n##_compare_key, \
31 .rbto_node_offset = offsetof(_t, _f), \
32 .rbto_context = NULL \
33 }; \
34 \
35 int \
36 _n##_compare_nodes(void *ctx, const void *n1, const void *n2) { \
37 return _cmp(n1, n2); \
38 } \
39 \
40 int \
41 _n##_compare_key(void *ctx, const void *n1, const void *key) { \
42 return _cmp(n1, key); \
43 } \
44 \
45 void \
46 _n##_rb_walktree(rb_tree_t *head, _n##_rb_walker_t func, void *arg) \
47 { \
48 _t *rb; \
49 /* Take advantage of the fact that the ipf code only uses this \
50 method to clear the tree, in order to do it more safely. */ \
51 while ((rb = rb_tree_iterate(head, NULL, RB_DIR_RIGHT)) != NULL) {\
52 rb_tree_remove_node(head, rb); \
53 func(rb, arg); \
54 } \
55 }
56
57 # define RBI_DELETE(_n, _h, _v) rb_tree_remove_node(_h, _v)
58 # define RBI_INIT(_n, _h) rb_tree_init(_h, &_n##_tree_ops)
59 # define RBI_INSERT(_n, _h, _v) rb_tree_insert_node(_h, _v)
60 # define RBI_ISEMPTY(_h) (rb_tree_iterate(_h, NULL, RB_DIR_RIGHT) == NULL)
61 # define RBI_SEARCH(_n, _h, _k) rb_tree_find_node(_h, _k)
62 # define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a)
63
64 #else
65
66 typedef enum rbcolour_e {
67 C_BLACK = 0,
68 C_RED = 1
69 } rbcolour_t;
70
71 #define RBI_LINK(_n, _t) \
72 struct _n##_rb_link { \
73 struct _t *left; \
74 struct _t *right; \
75 struct _t *parent; \
76 rbcolour_t colour; \
77 }
78
79 #define RBI_HEAD(_n, _t) \
80 struct _n##_rb_head { \
81 struct _t top; \
82 int count; \
83 int (* compare)(struct _t *, struct _t *); \
84 }
85
86 #define RBI_FIELD(_n) struct _n##_rb_link
87
88 #define RBI_CODE(_n, _t, _f, _cmp) \
89 \
90 _t RBI_ZERO(_n); \
91 \
92 typedef void (*_n##_rb_walker_t)(_t *, void *); \
93 \
94 _t * _n##_rb_delete(struct _n##_rb_head *, _t *); \
95 void _n##_rb_init(struct _n##_rb_head *); \
96 void _n##_rb_insert(struct _n##_rb_head *, _t *); \
97 _t * _n##_rb_search(struct _n##_rb_head *, void *); \
98 void _n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
99 \
100 static void \
101 rotate_left(struct _n##_rb_head *head, _t *node) \
102 { \
103 _t *parent, *tmp1, *tmp2; \
104 \
105 parent = node->_f.parent; \
106 tmp1 = node->_f.right; \
107 tmp2 = tmp1->_f.left; \
108 node->_f.right = tmp2; \
109 if (tmp2 != & _n##_rb_zero) \
110 tmp2->_f.parent = node; \
111 if (parent == & _n##_rb_zero) \
112 head->top._f.right = tmp1; \
113 else if (parent->_f.right == node) \
114 parent->_f.right = tmp1; \
115 else \
116 parent->_f.left = tmp1; \
117 tmp1->_f.left = node; \
118 tmp1->_f.parent = parent; \
119 node->_f.parent = tmp1; \
120 } \
121 \
122 static void \
123 rotate_right(struct _n##_rb_head *head, _t *node) \
124 { \
125 _t *parent, *tmp1, *tmp2; \
126 \
127 parent = node->_f.parent; \
128 tmp1 = node->_f.left; \
129 tmp2 = tmp1->_f.right; \
130 node->_f.left = tmp2; \
131 if (tmp2 != &_n##_rb_zero) \
132 tmp2->_f.parent = node; \
133 if (parent == &_n##_rb_zero) \
134 head->top._f.right = tmp1; \
135 else if (parent->_f.right == node) \
136 parent->_f.right = tmp1; \
137 else \
138 parent->_f.left = tmp1; \
139 tmp1->_f.right = node; \
140 tmp1->_f.parent = parent; \
141 node->_f.parent = tmp1; \
142 } \
143 \
144 void \
145 _n##_rb_insert(struct _n##_rb_head *head, _t *node) \
146 { \
147 _t *n, *parent, **p, *tmp1, *gparent; \
148 \
149 parent = &head->top; \
150 node->_f.left = &_n##_rb_zero; \
151 node->_f.right = &_n##_rb_zero; \
152 p = &head->top._f.right; \
153 while ((n = *p) != &_n##_rb_zero) { \
154 if (_cmp(node, n) < 0) \
155 p = &n->_f.left; \
156 else \
157 p = &n->_f.right; \
158 parent = n; \
159 } \
160 *p = node; \
161 node->_f.colour = C_RED; \
162 node->_f.parent = parent; \
163 \
164 while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
165 gparent = parent->_f.parent; \
166 if (parent == gparent->_f.left) { \
167 tmp1 = gparent->_f.right; \
168 if (tmp1->_f.colour == C_RED) { \
169 parent->_f.colour = C_BLACK; \
170 tmp1->_f.colour = C_BLACK; \
171 gparent->_f.colour = C_RED; \
172 node = gparent; \
173 } else { \
174 if (node == parent->_f.right) { \
175 node = parent; \
176 rotate_left(head, node); \
177 parent = node->_f.parent; \
178 } \
179 parent->_f.colour = C_BLACK; \
180 gparent->_f.colour = C_RED; \
181 rotate_right(head, gparent); \
182 } \
183 } else { \
184 tmp1 = gparent->_f.left; \
185 if (tmp1->_f.colour == C_RED) { \
186 parent->_f.colour = C_BLACK; \
187 tmp1->_f.colour = C_BLACK; \
188 gparent->_f.colour = C_RED; \
189 node = gparent; \
190 } else { \
191 if (node == parent->_f.left) { \
192 node = parent; \
193 rotate_right(head, node); \
194 parent = node->_f.parent; \
195 } \
196 parent->_f.colour = C_BLACK; \
197 gparent->_f.colour = C_RED; \
198 rotate_left(head, parent->_f.parent); \
199 } \
200 } \
201 parent = node->_f.parent; \
202 } \
203 head->top._f.right->_f.colour = C_BLACK; \
204 head->count++; \
205 } \
206 \
207 static void \
208 deleteblack(struct _n##_rb_head *head, _t *parent, _t *node) \
209 { \
210 _t *tmp; \
211 \
212 while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) && \
213 node != &head->top) { \
214 if (parent->_f.left == node) { \
215 tmp = parent->_f.right; \
216 if (tmp->_f.colour == C_RED) { \
217 tmp->_f.colour = C_BLACK; \
218 parent->_f.colour = C_RED; \
219 rotate_left(head, parent); \
220 tmp = parent->_f.right; \
221 } \
222 if ((tmp->_f.left == &_n##_rb_zero || \
223 tmp->_f.left->_f.colour == C_BLACK) && \
224 (tmp->_f.right == &_n##_rb_zero || \
225 tmp->_f.right->_f.colour == C_BLACK)) { \
226 tmp->_f.colour = C_RED; \
227 node = parent; \
228 parent = node->_f.parent; \
229 } else { \
230 if (tmp->_f.right == &_n##_rb_zero || \
231 tmp->_f.right->_f.colour == C_BLACK) {\
232 _t *tmp2 = tmp->_f.left; \
233 \
234 if (tmp2 != &_n##_rb_zero) \
235 tmp2->_f.colour = C_BLACK;\
236 tmp->_f.colour = C_RED; \
237 rotate_right(head, tmp); \
238 tmp = parent->_f.right; \
239 } \
240 tmp->_f.colour = parent->_f.colour; \
241 parent->_f.colour = C_BLACK; \
242 if (tmp->_f.right != &_n##_rb_zero) \
243 tmp->_f.right->_f.colour = C_BLACK;\
244 rotate_left(head, parent); \
245 node = head->top._f.right; \
246 } \
247 } else { \
248 tmp = parent->_f.left; \
249 if (tmp->_f.colour == C_RED) { \
250 tmp->_f.colour = C_BLACK; \
251 parent->_f.colour = C_RED; \
252 rotate_right(head, parent); \
253 tmp = parent->_f.left; \
254 } \
255 if ((tmp->_f.left == &_n##_rb_zero || \
256 tmp->_f.left->_f.colour == C_BLACK) && \
257 (tmp->_f.right == &_n##_rb_zero || \
258 tmp->_f.right->_f.colour == C_BLACK)) { \
259 tmp->_f.colour = C_RED; \
260 node = parent; \
261 parent = node->_f.parent; \
262 } else { \
263 if (tmp->_f.left == &_n##_rb_zero || \
264 tmp->_f.left->_f.colour == C_BLACK) {\
265 _t *tmp2 = tmp->_f.right; \
266 \
267 if (tmp2 != &_n##_rb_zero) \
268 tmp2->_f.colour = C_BLACK;\
269 tmp->_f.colour = C_RED; \
270 rotate_left(head, tmp); \
271 tmp = parent->_f.left; \
272 } \
273 tmp->_f.colour = parent->_f.colour; \
274 parent->_f.colour = C_BLACK; \
275 if (tmp->_f.left != &_n##_rb_zero) \
276 tmp->_f.left->_f.colour = C_BLACK;\
277 rotate_right(head, parent); \
278 node = head->top._f.right; \
279 break; \
280 } \
281 } \
282 } \
283 if (node != &_n##_rb_zero) \
284 node->_f.colour = C_BLACK; \
285 } \
286 \
287 _t * \
288 _n##_rb_delete(struct _n##_rb_head *head, _t *node) \
289 { \
290 _t *child, *parent, *old = node, *left; \
291 rbcolour_t color; \
292 \
293 if (node->_f.left == &_n##_rb_zero) { \
294 child = node->_f.right; \
295 } else if (node->_f.right == &_n##_rb_zero) { \
296 child = node->_f.left; \
297 } else { \
298 node = node->_f.right; \
299 while ((left = node->_f.left) != &_n##_rb_zero) \
300 node = left; \
301 child = node->_f.right; \
302 parent = node->_f.parent; \
303 color = node->_f.colour; \
304 if (child != &_n##_rb_zero) \
305 child->_f.parent = parent; \
306 if (parent != &_n##_rb_zero) { \
307 if (parent->_f.left == node) \
308 parent->_f.left = child; \
309 else \
310 parent->_f.right = child; \
311 } else { \
312 head->top._f.right = child; \
313 } \
314 if (node->_f.parent == old) \
315 parent = node; \
316 *node = *old; \
317 if (old->_f.parent != &_n##_rb_zero) { \
318 if (old->_f.parent->_f.left == old) \
319 old->_f.parent->_f.left = node; \
320 else \
321 old->_f.parent->_f.right = node; \
322 } else { \
323 head->top._f.right = child; \
324 } \
325 old->_f.left->_f.parent = node; \
326 if (old->_f.right != &_n##_rb_zero) \
327 old->_f.right->_f.parent = node; \
328 if (parent != &_n##_rb_zero) { \
329 left = parent; \
330 } \
331 goto colour; \
332 } \
333 parent = node->_f.parent; \
334 color= node->_f.colour; \
335 if (child != &_n##_rb_zero) \
336 child->_f.parent = parent; \
337 if (parent != &_n##_rb_zero) { \
338 if (parent->_f.left == node) \
339 parent->_f.left = child; \
340 else \
341 parent->_f.right = child; \
342 } else { \
343 head->top._f.right = child; \
344 } \
345 colour: \
346 if (color == C_BLACK) \
347 deleteblack(head, parent, node); \
348 head->count--; \
349 return old; \
350 } \
351 \
352 void \
353 _n##_rb_init(struct _n##_rb_head *head) \
354 { \
355 memset(head, 0, sizeof(*head)); \
356 memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero)); \
357 head->top._f.left = &_n##_rb_zero; \
358 head->top._f.right = &_n##_rb_zero; \
359 head->top._f.parent = &head->top; \
360 _n##_rb_zero._f.left = &_n##_rb_zero; \
361 _n##_rb_zero._f.right = &_n##_rb_zero; \
362 _n##_rb_zero._f.parent = &_n##_rb_zero; \
363 } \
364 \
365 void \
366 _n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
367 { \
368 _t *prev; \
369 _t *next; \
370 _t *node = head->top._f.right; \
371 _t *base; \
372 \
373 while (node != &_n##_rb_zero) \
374 node = node->_f.left; \
375 \
376 for (;;) { \
377 base = node; \
378 prev = node; \
379 while ((node->_f.parent->_f.right == node) && \
380 (node != &_n##_rb_zero)) { \
381 prev = node; \
382 node = node->_f.parent; \
383 } \
384 \
385 node = prev; \
386 for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
387 node = node->_f.left) \
388 prev = node; \
389 next = prev; \
390 \
391 if (node != &_n##_rb_zero) \
392 func(node, arg); \
393 \
394 node = next; \
395 if (node == &_n##_rb_zero) \
396 break; \
397 } \
398 } \
399 \
400 _t * \
401 _n##_rb_search(struct _n##_rb_head *head, void *key) \
402 { \
403 int match = 0; \
404 _t *node; \
405 node = head->top._f.right; \
406 while (node != &_n##_rb_zero) { \
407 match = _cmp(key, node); \
408 if (match == 0) \
409 break; \
410 if (match< 0) \
411 node = node->_f.left; \
412 else \
413 node = node->_f.right; \
414 } \
415 if (node == &_n##_rb_zero || match != 0) \
416 return (NULL); \
417 return (node); \
418 }
419
420 #define RBI_DELETE(_n, _h, _v) _n##_rb_delete(_h, _v)
421 #define RBI_INIT(_n, _h) _n##_rb_init(_h)
422 #define RBI_INSERT(_n, _h, _v) _n##_rb_insert(_h, _v)
423 #define RBI_ISEMPTY(_h) ((_h)->count == 0)
424 #define RBI_SEARCH(_n, _h, _k) _n##_rb_search(_h, _k)
425 #define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a)
426 #define RBI_ZERO(_n) _n##_rb_zero
427
428 #endif
429