2 * crit-bit tree implementation, does no allocations internally
3 * For more information on crit-bit trees: https://cr.yp.to/critbit.html
4 * Based on Adam Langley's adaptation of Dan Bernstein's public domain code
5 * git clone https://github.com/agl/critbit.git
9 static struct cb_node
*cb_node_of(const void *p
)
11 return (struct cb_node
*)((uintptr_t)p
- 1);
14 /* locate the best match, does not do a final comparision */
15 static struct cb_node
*cb_internal_best_match(struct cb_node
*p
,
16 const uint8_t *k
, size_t klen
)
18 while (1 & (uintptr_t)p
) {
19 struct cb_node
*q
= cb_node_of(p
);
20 uint8_t c
= q
->byte
< klen
? k
[q
->byte
] : 0;
21 size_t direction
= (1 + (q
->otherbits
| c
)) >> 8;
23 p
= q
->child
[direction
];
28 /* returns NULL if successful, existing cb_node if duplicate */
29 struct cb_node
*cb_insert(struct cb_tree
*t
, struct cb_node
*node
, size_t klen
)
31 size_t newbyte
, newotherbits
;
34 struct cb_node
**wherep
, *p
;
36 assert(!((uintptr_t)node
& 1)); /* allocations must be aligned */
38 if (!t
->root
) { /* insert into empty tree */
40 return NULL
; /* success */
43 /* see if a node already exists */
44 p
= cb_internal_best_match(t
->root
, node
->k
, klen
);
46 /* find first differing byte */
47 for (newbyte
= 0; newbyte
< klen
; newbyte
++) {
48 if (p
->k
[newbyte
] != node
->k
[newbyte
])
49 goto different_byte_found
;
51 return p
; /* element exists, let user deal with it */
54 newotherbits
= p
->k
[newbyte
] ^ node
->k
[newbyte
];
55 newotherbits
|= newotherbits
>> 1;
56 newotherbits
|= newotherbits
>> 2;
57 newotherbits
|= newotherbits
>> 4;
58 newotherbits
= (newotherbits
& ~(newotherbits
>> 1)) ^ 255;
60 newdirection
= (1 + (newotherbits
| c
)) >> 8;
63 node
->otherbits
= newotherbits
;
64 node
->child
[1 - newdirection
] = node
;
66 /* find a place to insert it */
73 if (!(1 & (uintptr_t)p
))
76 if (q
->byte
> newbyte
)
78 if (q
->byte
== newbyte
&& q
->otherbits
> newotherbits
)
80 c
= q
->byte
< klen
? node
->k
[q
->byte
] : 0;
81 direction
= (1 + (q
->otherbits
| c
)) >> 8;
82 wherep
= q
->child
+ direction
;
85 node
->child
[newdirection
] = *wherep
;
86 *wherep
= (struct cb_node
*)(1 + (uintptr_t)node
);
88 return NULL
; /* success */
91 struct cb_node
*cb_lookup(struct cb_tree
*t
, const uint8_t *k
, size_t klen
)
93 struct cb_node
*p
= cb_internal_best_match(t
->root
, k
, klen
);
95 return p
&& !memcmp(p
->k
, k
, klen
) ? p
: NULL
;
98 struct cb_node
*cb_unlink(struct cb_tree
*t
, const uint8_t *k
, size_t klen
)
100 struct cb_node
**wherep
= &t
->root
;
101 struct cb_node
**whereq
= NULL
;
102 struct cb_node
*q
= NULL
;
103 size_t direction
= 0;
105 struct cb_node
*p
= t
->root
;
107 if (!p
) return NULL
; /* empty tree, nothing to delete */
109 /* traverse to find best match, keeping link to parent */
110 while (1 & (uintptr_t)p
) {
113 c
= q
->byte
< klen
? k
[q
->byte
] : 0;
114 direction
= (1 + (q
->otherbits
| c
)) >> 8;
115 wherep
= q
->child
+ direction
;
119 if (memcmp(p
->k
, k
, klen
))
120 return NULL
; /* no match, nothing unlinked */
122 /* found an exact match */
123 if (whereq
) /* update parent */
124 *whereq
= q
->child
[1 - direction
];
130 static enum cb_next
cb_descend(struct cb_node
*p
, cb_iter fn
, void *arg
)
132 if (1 & (uintptr_t)p
) {
133 struct cb_node
*q
= cb_node_of(p
);
134 enum cb_next n
= cb_descend(q
->child
[0], fn
, arg
);
136 return n
== CB_BREAK
? n
: cb_descend(q
->child
[1], fn
, arg
);
142 void cb_each(struct cb_tree
*t
, const uint8_t *kpfx
, size_t klen
,
143 cb_iter fn
, void *arg
)
145 struct cb_node
*p
= t
->root
;
146 struct cb_node
*top
= p
;
149 if (!p
) return; /* empty tree */
151 /* Walk tree, maintaining top pointer */
152 while (1 & (uintptr_t)p
) {
153 struct cb_node
*q
= cb_node_of(p
);
154 uint8_t c
= q
->byte
< klen
? kpfx
[q
->byte
] : 0;
155 size_t direction
= (1 + (q
->otherbits
| c
)) >> 8;
157 p
= q
->child
[direction
];
162 for (i
= 0; i
< klen
; i
++) {
163 if (p
->k
[i
] != kpfx
[i
])
164 return; /* "best" match failed */
166 cb_descend(top
, fn
, arg
);