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