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