File Coverage

lib/Net/BART/bart.h
Criterion Covered Total %
statement 322 388 82.9
branch 121 192 63.0
condition n/a
subroutine n/a
pod n/a
total 443 580 76.3


line stmt bran cond sub pod time code
1             /*
2             * bart.h - Balanced Routing Tables (BART) implementation in C
3             *
4             * A multibit trie with fixed 8-bit strides for fast IPv4/IPv6
5             * longest-prefix-match lookups.
6             */
7              
8             #ifndef BART_H
9             #define BART_H
10              
11             #include
12             #include
13             #include
14              
15             /* ---- BitSet256 ---- */
16              
17             typedef struct {
18             uint64_t w[4];
19             } bitset256_t;
20              
21 326           static inline void bs256_init(bitset256_t *b) {
22 326           b->w[0] = b->w[1] = b->w[2] = b->w[3] = 0;
23 326           }
24              
25 2079           static inline void bs256_set(bitset256_t *b, int bit) {
26 2079           b->w[bit >> 6] |= (1ULL << (bit & 63));
27 2079           }
28              
29 1           static inline void bs256_clear(bitset256_t *b, int bit) {
30 1           b->w[bit >> 6] &= ~(1ULL << (bit & 63));
31 1           }
32              
33 1157           static inline int bs256_test(const bitset256_t *b, int bit) {
34 1157           return (b->w[bit >> 6] & (1ULL << (bit & 63))) ? 1 : 0;
35             }
36              
37             static inline int bs256_is_empty(const bitset256_t *b) {
38             return !(b->w[0] | b->w[1] | b->w[2] | b->w[3]);
39             }
40              
41 1267           static inline int popcount64(uint64_t x) {
42             #if defined(__GNUC__) || defined(__clang__)
43 1267           return __builtin_popcountll(x);
44             #else
45             x = x - ((x >> 1) & 0x5555555555555555ULL);
46             x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
47             return (int)(((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL) * 0x0101010101010101ULL >> 56);
48             #endif
49             }
50              
51             /* Rank: count of set bits in positions 0..idx (inclusive) */
52 869           static inline int bs256_rank(const bitset256_t *b, int idx) {
53 869           int word = idx >> 6;
54 869           int bit = idx & 63;
55 869           int count = 0;
56              
57 869           switch (word) {
58 65           case 3: count += popcount64(b->w[2]); /* fallthrough */
59 134           case 2: count += popcount64(b->w[1]); /* fallthrough */
60 199           case 1: count += popcount64(b->w[0]); /* fallthrough */
61 869           case 0: break;
62             }
63              
64 869 100         uint64_t mask = (bit == 63) ? ~0ULL : ((1ULL << (bit + 1)) - 1);
65 869           count += popcount64(b->w[word] & mask);
66 869           return count;
67             }
68              
69 7           static inline int bitlen64(uint64_t x) {
70             #if defined(__GNUC__) || defined(__clang__)
71 7 50         return x ? (64 - __builtin_clzll(x)) : 0;
72             #else
73             if (!x) return 0;
74             int n = 0;
75             if (x >> 32) { n += 32; x >>= 32; }
76             if (x >> 16) { n += 16; x >>= 16; }
77             if (x >> 8) { n += 8; x >>= 8; }
78             if (x >> 4) { n += 4; x >>= 4; }
79             if (x >> 2) { n += 2; x >>= 2; }
80             if (x >> 1) { n += 1; x >>= 1; }
81             return n + (int)x;
82             #endif
83             }
84              
85             /* IntersectionTop: highest set bit in (a AND b), or -1 */
86 13           static inline int bs256_intersection_top(const bitset256_t *a, const bitset256_t *b) {
87             uint64_t w;
88 13 50         w = a->w[3] & b->w[3]; if (w) return 192 + bitlen64(w) - 1;
89 13 50         w = a->w[2] & b->w[2]; if (w) return 128 + bitlen64(w) - 1;
90 13 50         w = a->w[1] & b->w[1]; if (w) return 64 + bitlen64(w) - 1;
91 13 100         w = a->w[0] & b->w[0]; if (w) return bitlen64(w) - 1;
92 6           return -1;
93             }
94              
95 3           static inline int bs256_intersects(const bitset256_t *a, const bitset256_t *b) {
96 3           return ((a->w[0] & b->w[0]) | (a->w[1] & b->w[1]) |
97 3           (a->w[2] & b->w[2]) | (a->w[3] & b->w[3])) ? 1 : 0;
98             }
99              
100             /* ---- ART index mapping ---- */
101              
102 2           static inline int pfx_to_idx(int octet, int pfx_len) {
103 2           return (octet >> (8 - pfx_len)) + (1 << pfx_len);
104             }
105              
106 16           static inline int octet_to_idx(int octet) {
107 16           return (octet >> 1) + 128;
108             }
109              
110             /* ---- LPM Lookup Table ---- */
111              
112             /* For each idx in [0..255], ancestor_tbl[idx] has idx and all its
113             binary-tree ancestors set. */
114             static bitset256_t ancestor_tbl[256];
115             static int ancestor_tbl_init = 0;
116              
117 12           static void init_ancestor_tbl(void) {
118 12 100         if (ancestor_tbl_init) return;
119 257 100         for (int idx = 0; idx < 256; idx++) {
120 256           bs256_init(&ancestor_tbl[idx]);
121 2049 100         for (int i = idx; i > 0; i >>= 1) {
122 1793           bs256_set(&ancestor_tbl[idx], i);
123             }
124             }
125 1           ancestor_tbl_init = 1;
126             }
127              
128             /* ---- Sparse Array 256 ---- */
129             /* Stores up to 256 (void*) values indexed by 0..255 using popcount compression. */
130              
131             typedef struct {
132             bitset256_t bits;
133             void **items;
134             int len;
135             int cap;
136             } sparse256_t;
137              
138 70           static void sparse256_init(sparse256_t *s) {
139 70           bs256_init(&s->bits);
140 70           s->items = NULL;
141 70           s->len = 0;
142 70           s->cap = 0;
143 70           }
144              
145 70           static void sparse256_free(sparse256_t *s) {
146 70           free(s->items);
147 70           s->items = NULL;
148 70           s->len = s->cap = 0;
149 70           }
150              
151 859           static inline void* sparse256_get(const sparse256_t *s, int idx) {
152 859 100         if (!bs256_test(&s->bits, idx)) return NULL;
153 571           int rank = bs256_rank(&s->bits, idx) - 1;
154 571           return s->items[rank];
155             }
156              
157             /* Returns 1 if new, 0 if updated. If old_val is non-NULL, stores previous value on update. */
158 297           static int sparse256_insert_ex(sparse256_t *s, int idx, void *val, void **old_val) {
159 297 100         if (bs256_test(&s->bits, idx)) {
160 11           int rank = bs256_rank(&s->bits, idx) - 1;
161 11 50         if (old_val) *old_val = s->items[rank];
162 11           s->items[rank] = val;
163 11           return 0;
164             }
165 286           bs256_set(&s->bits, idx);
166 286           int rank = bs256_rank(&s->bits, idx) - 1;
167             /* grow if needed */
168 286 100         if (s->len >= s->cap) {
169 36 100         int newcap = s->cap ? s->cap * 2 : 4;
170 36           s->items = realloc(s->items, newcap * sizeof(void*));
171 36           s->cap = newcap;
172             }
173             /* shift right */
174 286           memmove(&s->items[rank + 1], &s->items[rank], (s->len - rank) * sizeof(void*));
175 286           s->items[rank] = val;
176 286           s->len++;
177 286           return 1;
178             }
179              
180 294           static int sparse256_insert(sparse256_t *s, int idx, void *val) {
181 294           return sparse256_insert_ex(s, idx, val, NULL);
182             }
183              
184             /* Returns old value or NULL */
185 1           static void* sparse256_delete(sparse256_t *s, int idx) {
186 1 50         if (!bs256_test(&s->bits, idx)) return NULL;
187 1           int rank = bs256_rank(&s->bits, idx) - 1;
188 1           void *old = s->items[rank];
189 1           memmove(&s->items[rank], &s->items[rank + 1], (s->len - rank - 1) * sizeof(void*));
190 1           s->len--;
191 1           bs256_clear(&s->bits, idx);
192 1           return old;
193             }
194              
195             /* ---- BART Nodes ---- */
196              
197             /* Node types */
198             #define NODE_BART 0
199             #define NODE_LEAF 1
200             #define NODE_FRINGE 2
201              
202             typedef struct bart_node {
203             sparse256_t prefixes; /* idx -> SV* values */
204             sparse256_t children; /* octet -> node ptr */
205             } bart_node_t;
206              
207             typedef struct leaf_node {
208             uint8_t addr[16]; /* address bytes (4 for v4, 16 for v6) */
209             int prefix_len;
210             int addr_len; /* 4 or 16 */
211             void *value; /* SV* */
212             } leaf_node_t;
213              
214             typedef struct fringe_node {
215             void *value; /* SV* */
216             } fringe_node_t;
217              
218             /* Tagged pointer: use low 2 bits for type tag (pointers are aligned) */
219             #define TAG_BITS 2
220             #define TAG_MASK 3
221              
222 289           static inline void* tag_ptr(void *p, int tag) {
223 289           return (void*)((uintptr_t)p | tag);
224             }
225              
226 1117           static inline void* untag_ptr(void *p) {
227 1117           return (void*)((uintptr_t)p & ~(uintptr_t)TAG_MASK);
228             }
229              
230 1117           static inline int ptr_tag(void *p) {
231 1117           return (int)((uintptr_t)p & TAG_MASK);
232             }
233              
234             /* ---- BART Node operations ---- */
235              
236 35           static bart_node_t* bart_node_new(void) {
237 35           bart_node_t *n = calloc(1, sizeof(bart_node_t));
238 35           sparse256_init(&n->prefixes);
239 35           sparse256_init(&n->children);
240 35           return n;
241             }
242              
243 9           static leaf_node_t* leaf_node_new(const uint8_t *addr, int addr_len, int prefix_len, void *value) {
244 9           leaf_node_t *l = malloc(sizeof(leaf_node_t));
245 9           memset(l->addr, 0, 16);
246 9           memcpy(l->addr, addr, addr_len);
247 9           l->prefix_len = prefix_len;
248 9           l->addr_len = addr_len;
249 9           l->value = value;
250 9           return l;
251             }
252              
253 269           static fringe_node_t* fringe_node_new(void *value) {
254 269           fringe_node_t *f = malloc(sizeof(fringe_node_t));
255 269           f->value = value;
256 269           return f;
257             }
258              
259 1           static inline int bart_node_is_empty(const bart_node_t *n) {
260 1 50         return n->prefixes.len == 0 && n->children.len == 0;
    0          
261             }
262              
263             /* LPM at a single node for a given octet */
264 13           static inline void* bart_node_lpm(const bart_node_t *n, int octet, int *found) {
265 13           int idx = octet_to_idx(octet);
266 13           int top = bs256_intersection_top(&n->prefixes.bits, &ancestor_tbl[idx]);
267 13 100         if (top >= 0) {
268 7           *found = 1;
269 7           return sparse256_get(&n->prefixes, top);
270             }
271 6           *found = 0;
272 6           return NULL;
273             }
274              
275             /* LPM test (any match?) */
276 3           static inline int bart_node_lpm_test(const bart_node_t *n, int octet) {
277 3           int idx = octet_to_idx(octet);
278 3           return bs256_intersects(&n->prefixes.bits, &ancestor_tbl[idx]);
279             }
280              
281             /* ---- Leaf containment check ---- */
282              
283 4           static int leaf_contains_ip(const leaf_node_t *leaf, const uint8_t *ip) {
284 4           int full_bytes = leaf->prefix_len >> 3;
285 4           int remaining = leaf->prefix_len & 7;
286 4 100         if (memcmp(leaf->addr, ip, full_bytes) != 0) return 0;
287 2 50         if (remaining) {
288 0           uint8_t mask = (0xFF << (8 - remaining)) & 0xFF;
289 0 0         if ((leaf->addr[full_bytes] & mask) != (ip[full_bytes] & mask)) return 0;
290             }
291 2           return 1;
292             }
293              
294 6           static int leaf_matches_prefix(const leaf_node_t *leaf, const uint8_t *addr, int prefix_len) {
295 6 100         if (leaf->prefix_len != prefix_len) return 0;
296 3           int full_bytes = prefix_len >> 3;
297 3 100         if (memcmp(leaf->addr, addr, full_bytes) != 0) return 0;
298 1           int remaining = prefix_len & 7;
299 1 50         if (remaining) {
300 1           uint8_t mask = (0xFF << (8 - remaining)) & 0xFF;
301 1 50         if ((leaf->addr[full_bytes] & mask) != (addr[full_bytes] & mask)) return 0;
302             }
303 0           return 1;
304             }
305              
306             /* ---- BART Table ---- */
307              
308             typedef struct {
309             bart_node_t *root4;
310             bart_node_t *root6;
311             int size4;
312             int size6;
313             } bart_table_t;
314              
315 12           static bart_table_t* bart_table_new(void) {
316 12           init_ancestor_tbl();
317 12           bart_table_t *t = malloc(sizeof(bart_table_t));
318 12           t->root4 = bart_node_new();
319 12           t->root6 = bart_node_new();
320 12           t->size4 = 0;
321 12           t->size6 = 0;
322 12           return t;
323             }
324              
325             /* Forward declarations for recursive free */
326             static void bart_node_free_recursive(bart_node_t *node);
327              
328 35           static void bart_node_free_recursive(bart_node_t *node) {
329 35 50         if (!node) return;
330             /* Free children */
331 312 100         for (int i = 0; i < node->children.len; i++) {
332 277           void *tagged = node->children.items[i];
333 277           int tag = ptr_tag(tagged);
334 277           void *ptr = untag_ptr(tagged);
335 277 100         if (tag == NODE_BART) {
336 11           bart_node_free_recursive((bart_node_t*)ptr);
337             } else {
338 266           free(ptr); /* leaf or fringe */
339             }
340             }
341             /* Note: prefix values (SV*) are freed by Perl via reference counting */
342 35           sparse256_free(&node->prefixes);
343 35           sparse256_free(&node->children);
344 35           free(node);
345             }
346              
347 12           static void bart_table_free(bart_table_t *t) {
348 12 50         if (!t) return;
349 12           bart_node_free_recursive(t->root4);
350 12           bart_node_free_recursive(t->root6);
351 12           free(t);
352             }
353              
354             /* ---- Insert ---- */
355              
356             /* Insert: returns 1 if new, 0 if updated. old_val receives replaced value on update. */
357             static int bart_insert(bart_node_t *node, const uint8_t *addr, int addr_len,
358             int prefix_len, int depth, void *value, void **old_val);
359             static int bart_insert_fringe(bart_node_t *node, const uint8_t *addr, int addr_len,
360             int prefix_len, int depth, void *value, void **old_val);
361              
362 802           static int bart_insert(bart_node_t *node, const uint8_t *addr, int addr_len,
363             int prefix_len, int depth, void *value, void **old_val) {
364 802           int strides = prefix_len >> 3;
365 802           int lastbits = prefix_len & 7;
366              
367 802 100         if (prefix_len == 0) {
368 1           return sparse256_insert_ex(&node->prefixes, 1, value, old_val);
369             }
370              
371 801 100         if (lastbits && depth == strides) {
    100          
372 2           int idx = pfx_to_idx(addr[depth], lastbits);
373 2           return sparse256_insert_ex(&node->prefixes, idx, value, old_val);
374             }
375              
376 799 100         if (!lastbits && depth == strides - 1) {
    100          
377 270           return bart_insert_fringe(node, addr, addr_len, prefix_len, depth, value, old_val);
378             }
379              
380             /* Navigate */
381 529           int octet = addr[depth];
382 529           void *tagged = sparse256_get(&node->children, octet);
383              
384 529 100         if (!tagged) {
385 9           leaf_node_t *leaf = leaf_node_new(addr, addr_len, prefix_len, value);
386 9           sparse256_insert(&node->children, octet, tag_ptr(leaf, NODE_LEAF));
387 9           return 1;
388             }
389              
390 520           int tag = ptr_tag(tagged);
391 520           void *child = untag_ptr(tagged);
392              
393 520 100         if (tag == NODE_LEAF) {
394 6           leaf_node_t *leaf = (leaf_node_t*)child;
395 6 50         if (leaf_matches_prefix(leaf, addr, prefix_len)) {
396 0 0         if (old_val) *old_val = leaf->value;
397 0           leaf->value = value;
398 0           return 0;
399             }
400 6           bart_node_t *new_node = bart_node_new();
401 6           bart_insert(new_node, leaf->addr, leaf->addr_len, leaf->prefix_len, depth + 1, leaf->value, NULL);
402 6           sparse256_insert(&node->children, octet, tag_ptr(new_node, NODE_BART));
403 6           free(leaf);
404 6           return bart_insert(new_node, addr, addr_len, prefix_len, depth + 1, value, old_val);
405             }
406              
407 514 100         if (tag == NODE_FRINGE) {
408 5           fringe_node_t *fringe = (fringe_node_t*)child;
409 5 50         if (!lastbits && depth == strides - 1) {
    50          
410 0 0         if (old_val) *old_val = fringe->value;
411 0           fringe->value = value;
412 0           return 0;
413             }
414 5           bart_node_t *new_node = bart_node_new();
415 5           sparse256_insert(&new_node->prefixes, 1, fringe->value);
416 5           sparse256_insert(&node->children, octet, tag_ptr(new_node, NODE_BART));
417 5           free(fringe);
418 5           return bart_insert(new_node, addr, addr_len, prefix_len, depth + 1, value, old_val);
419             }
420              
421             /* NODE_BART */
422 509           return bart_insert((bart_node_t*)child, addr, addr_len, prefix_len, depth + 1, value, old_val);
423             }
424              
425 270           static int bart_insert_fringe(bart_node_t *node, const uint8_t *addr, int addr_len,
426             int prefix_len, int depth, void *value, void **old_val) {
427 270           int octet = addr[depth];
428 270           void *tagged = sparse256_get(&node->children, octet);
429              
430 270 100         if (!tagged) {
431 269           fringe_node_t *f = fringe_node_new(value);
432 269           sparse256_insert(&node->children, octet, tag_ptr(f, NODE_FRINGE));
433 269           return 1;
434             }
435              
436 1           int tag = ptr_tag(tagged);
437 1           void *child = untag_ptr(tagged);
438              
439 1 50         if (tag == NODE_FRINGE) {
440 1 50         if (old_val) *old_val = ((fringe_node_t*)child)->value;
441 1           ((fringe_node_t*)child)->value = value;
442 1           return 0;
443             }
444 0 0         if (tag == NODE_BART) {
445 0           return sparse256_insert_ex(&((bart_node_t*)child)->prefixes, 1, value, old_val);
446             }
447 0 0         if (tag == NODE_LEAF) {
448 0           leaf_node_t *leaf = (leaf_node_t*)child;
449 0           bart_node_t *new_node = bart_node_new();
450 0           bart_insert(new_node, leaf->addr, leaf->addr_len, leaf->prefix_len, depth + 1, leaf->value, NULL);
451 0           sparse256_insert(&new_node->prefixes, 1, value);
452 0           sparse256_insert(&node->children, octet, tag_ptr(new_node, NODE_BART));
453 0           free(leaf);
454 0           return 1;
455             }
456 0           return 0;
457             }
458              
459             /* ---- Lookup (LPM) ---- */
460              
461             typedef struct {
462             bart_node_t *node;
463             int octet;
464             } stack_entry_t;
465              
466 18           static void* bart_lookup(bart_table_t *t, const uint8_t *ip, int is_ipv6, int *found) {
467 18 100         bart_node_t *root = is_ipv6 ? t->root6 : t->root4;
468 18 100         int max_depth = is_ipv6 ? 16 : 4;
469              
470             stack_entry_t stack[17]; /* max 16 for IPv6 + 1 */
471 18           int sp = 0;
472 18           bart_node_t *node = root;
473              
474 43 50         for (int depth = 0; depth < max_depth; depth++) {
475 43           int octet = ip[depth];
476 43           stack[sp].node = node;
477 43           stack[sp].octet = octet;
478 43           sp++;
479              
480 43           void *tagged = sparse256_get(&node->children, octet);
481 43 100         if (!tagged) break;
482              
483 35           int tag = ptr_tag(tagged);
484 35           void *child = untag_ptr(tagged);
485              
486 35 100         if (tag == NODE_FRINGE) {
487 6           *found = 1;
488 6           return ((fringe_node_t*)child)->value;
489             }
490 29 100         if (tag == NODE_LEAF) {
491 4           leaf_node_t *leaf = (leaf_node_t*)child;
492 4 100         if (leaf_contains_ip(leaf, ip)) {
493 2           *found = 1;
494 2           return leaf->value;
495             }
496 2           break;
497             }
498 25           node = (bart_node_t*)child;
499             }
500              
501             /* Backtrack LPM */
502 16 100         for (int i = sp - 1; i >= 0; i--) {
503             int ok;
504 13           void *val = bart_node_lpm(stack[i].node, stack[i].octet, &ok);
505 13 100         if (ok) {
506 7           *found = 1;
507 7           return val;
508             }
509             }
510              
511 3           *found = 0;
512 3           return NULL;
513             }
514              
515             /* ---- Contains ---- */
516              
517 3           static int bart_contains(bart_table_t *t, const uint8_t *ip, int is_ipv6) {
518 3 50         bart_node_t *root = is_ipv6 ? t->root6 : t->root4;
519 3 50         int max_depth = is_ipv6 ? 16 : 4;
520 3           bart_node_t *node = root;
521              
522 3 50         for (int depth = 0; depth < max_depth; depth++) {
523 3           int octet = ip[depth];
524 3 50         if (bart_node_lpm_test(node, octet)) return 1;
525              
526 3           void *tagged = sparse256_get(&node->children, octet);
527 3 100         if (!tagged) return 0;
528              
529 2           int tag = ptr_tag(tagged);
530 2           void *child = untag_ptr(tagged);
531              
532 2 50         if (tag == NODE_FRINGE) return 1;
533 0 0         if (tag == NODE_LEAF) return leaf_contains_ip((leaf_node_t*)child, ip);
534 0           node = (bart_node_t*)child;
535             }
536 0           return 0;
537             }
538              
539             /* ---- Exact match (Get) ---- */
540              
541 3           static void* bart_get(bart_table_t *t, const uint8_t *addr, int prefix_len,
542             int is_ipv6, int *found) {
543 3 50         bart_node_t *root = is_ipv6 ? t->root6 : t->root4;
544 3           bart_node_t *node = root;
545              
546 3           int strides = prefix_len >> 3;
547 3           int lastbits = prefix_len & 7;
548              
549 3 50         if (prefix_len == 0) {
550 0           void *v = sparse256_get(&node->prefixes, 1);
551 0           *found = (v != NULL);
552 0           return v;
553             }
554              
555 3           for (int depth = 0; ; depth++) {
556 4 50         if (lastbits && depth == strides) {
    0          
557 0           int idx = pfx_to_idx(addr[depth], lastbits);
558 0           void *v = sparse256_get(&node->prefixes, idx);
559 0           *found = (v != NULL);
560 0           return v;
561             }
562              
563 4 50         if (!lastbits && depth == strides - 1) {
    100          
564 3           void *tagged = sparse256_get(&node->children, addr[depth]);
565 3 100         if (!tagged) { *found = 0; return NULL; }
566 2           int tag = ptr_tag(tagged);
567 2           void *child = untag_ptr(tagged);
568 2 100         if (tag == NODE_FRINGE) {
569 1           *found = 1;
570 1           return ((fringe_node_t*)child)->value;
571             }
572 1 50         if (tag == NODE_BART) {
573 1           void *v = sparse256_get(&((bart_node_t*)child)->prefixes, 1);
574 1           *found = (v != NULL);
575 1           return v;
576             }
577 0           *found = 0;
578 0           return NULL;
579             }
580              
581             /* Navigate */
582 1           void *tagged = sparse256_get(&node->children, addr[depth]);
583 1 50         if (!tagged) { *found = 0; return NULL; }
584 1           int tag = ptr_tag(tagged);
585 1           void *child = untag_ptr(tagged);
586              
587 1 50         if (tag == NODE_LEAF) {
588 0 0         if (leaf_matches_prefix((leaf_node_t*)child, addr, prefix_len)) {
589 0           *found = 1;
590 0           return ((leaf_node_t*)child)->value;
591             }
592 0           *found = 0;
593 0           return NULL;
594             }
595 1 50         if (tag == NODE_FRINGE) { *found = 0; return NULL; }
596 1           node = (bart_node_t*)child;
597             }
598             }
599              
600             /* ---- Delete ---- */
601              
602 2           static void* bart_delete(bart_node_t *node, const uint8_t *addr,
603             int prefix_len, int depth, int *found) {
604 2           int strides = prefix_len >> 3;
605 2           int lastbits = prefix_len & 7;
606              
607 2 50         if (prefix_len == 0) {
608 0           void *old = sparse256_delete(&node->prefixes, 1);
609 0           *found = (old != NULL);
610 0           return old;
611             }
612              
613 2 50         if (lastbits && depth == strides) {
    0          
614 0           int idx = pfx_to_idx(addr[depth], lastbits);
615 0           void *old = sparse256_delete(&node->prefixes, idx);
616 0           *found = (old != NULL);
617 0           return old;
618             }
619              
620 2 50         if (!lastbits && depth == strides - 1) {
    100          
621 1           int octet = addr[depth];
622 1           void *tagged = sparse256_get(&node->children, octet);
623 1 50         if (!tagged) { *found = 0; return NULL; }
624 1           int tag = ptr_tag(tagged);
625 1           void *child = untag_ptr(tagged);
626              
627 1 50         if (tag == NODE_FRINGE) {
628 1           void *val = ((fringe_node_t*)child)->value;
629 1           sparse256_delete(&node->children, octet);
630 1           free(child);
631 1           *found = 1;
632 1           return val;
633             }
634 0 0         if (tag == NODE_BART) {
635 0           bart_node_t *bn = (bart_node_t*)child;
636 0           void *old = sparse256_delete(&bn->prefixes, 1);
637 0 0         if (old && bart_node_is_empty(bn)) {
    0          
638 0           sparse256_delete(&node->children, octet);
639 0           bart_node_free_recursive(bn);
640             }
641 0           *found = (old != NULL);
642 0           return old;
643             }
644 0           *found = 0;
645 0           return NULL;
646             }
647              
648             /* Navigate */
649 1           int octet = addr[depth];
650 1           void *tagged = sparse256_get(&node->children, octet);
651 1 50         if (!tagged) { *found = 0; return NULL; }
652 1           int tag = ptr_tag(tagged);
653 1           void *child = untag_ptr(tagged);
654              
655 1 50         if (tag == NODE_LEAF) {
656 0           leaf_node_t *leaf = (leaf_node_t*)child;
657 0 0         if (leaf_matches_prefix(leaf, addr, prefix_len)) {
658 0           void *val = leaf->value;
659 0           sparse256_delete(&node->children, octet);
660 0           free(leaf);
661 0           *found = 1;
662 0           return val;
663             }
664 0           *found = 0;
665 0           return NULL;
666             }
667 1 50         if (tag == NODE_FRINGE) { *found = 0; return NULL; }
668              
669 1           bart_node_t *bn = (bart_node_t*)child;
670 1           void *val = bart_delete(bn, addr, prefix_len, depth + 1, found);
671 1 50         if (*found && bart_node_is_empty(bn)) {
    50          
672 0           sparse256_delete(&node->children, octet);
673 0           bart_node_free_recursive(bn);
674             }
675 1           return val;
676             }
677              
678             /* ---- IP Parsing helpers ---- */
679              
680 295           static int parse_ipv4(const char *str, uint8_t *out) {
681             int a, b, c, d;
682 295 50         if (sscanf(str, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
683 0           return 0;
684 295           out[0] = (uint8_t)a; out[1] = (uint8_t)b;
685 295           out[2] = (uint8_t)c; out[3] = (uint8_t)d;
686 295           return 1;
687             }
688              
689 280           static void mask_prefix(uint8_t *addr, int addr_len, int prefix_len) {
690 280           int full = prefix_len >> 3;
691 280           int rem = prefix_len & 7;
692 280 100         if (rem && full < addr_len) {
    50          
693 2           addr[full] &= (0xFF << (8 - rem)) & 0xFF;
694 2           full++;
695             }
696 622 100         for (int i = full; i < addr_len; i++) addr[i] = 0;
697 280           }
698              
699             #endif /* BART_H */