git
/
cbtree.c
136 строк · 3.4 Кб
1/*
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
6*/
7#include "git-compat-util.h"
8#include "cbtree.h"
9
10static struct cb_node *cb_node_of(const void *p)
11{
12return (struct cb_node *)((uintptr_t)p - 1);
13}
14
15/* locate the best match, does not do a final comparision */
16static struct cb_node *cb_internal_best_match(struct cb_node *p,
17const uint8_t *k, size_t klen)
18{
19while (1 & (uintptr_t)p) {
20struct cb_node *q = cb_node_of(p);
21uint8_t c = q->byte < klen ? k[q->byte] : 0;
22size_t direction = (1 + (q->otherbits | c)) >> 8;
23
24p = q->child[direction];
25}
26return p;
27}
28
29/* returns NULL if successful, existing cb_node if duplicate */
30struct cb_node *cb_insert(struct cb_tree *t, struct cb_node *node, size_t klen)
31{
32size_t newbyte, newotherbits;
33uint8_t c;
34int newdirection;
35struct cb_node **wherep, *p;
36
37assert(!((uintptr_t)node & 1)); /* allocations must be aligned */
38
39if (!t->root) { /* insert into empty tree */
40t->root = node;
41return NULL; /* success */
42}
43
44/* see if a node already exists */
45p = cb_internal_best_match(t->root, node->k, klen);
46
47/* find first differing byte */
48for (newbyte = 0; newbyte < klen; newbyte++) {
49if (p->k[newbyte] != node->k[newbyte])
50goto different_byte_found;
51}
52return p; /* element exists, let user deal with it */
53
54different_byte_found:
55newotherbits = p->k[newbyte] ^ node->k[newbyte];
56newotherbits |= newotherbits >> 1;
57newotherbits |= newotherbits >> 2;
58newotherbits |= newotherbits >> 4;
59newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
60c = p->k[newbyte];
61newdirection = (1 + (newotherbits | c)) >> 8;
62
63node->byte = newbyte;
64node->otherbits = newotherbits;
65node->child[1 - newdirection] = node;
66
67/* find a place to insert it */
68wherep = &t->root;
69for (;;) {
70struct cb_node *q;
71size_t direction;
72
73p = *wherep;
74if (!(1 & (uintptr_t)p))
75break;
76q = cb_node_of(p);
77if (q->byte > newbyte)
78break;
79if (q->byte == newbyte && q->otherbits > newotherbits)
80break;
81c = q->byte < klen ? node->k[q->byte] : 0;
82direction = (1 + (q->otherbits | c)) >> 8;
83wherep = q->child + direction;
84}
85
86node->child[newdirection] = *wherep;
87*wherep = (struct cb_node *)(1 + (uintptr_t)node);
88
89return NULL; /* success */
90}
91
92struct cb_node *cb_lookup(struct cb_tree *t, const uint8_t *k, size_t klen)
93{
94struct cb_node *p = cb_internal_best_match(t->root, k, klen);
95
96return p && !memcmp(p->k, k, klen) ? p : NULL;
97}
98
99static enum cb_next cb_descend(struct cb_node *p, cb_iter fn, void *arg)
100{
101if (1 & (uintptr_t)p) {
102struct cb_node *q = cb_node_of(p);
103enum cb_next n = cb_descend(q->child[0], fn, arg);
104
105return n == CB_BREAK ? n : cb_descend(q->child[1], fn, arg);
106} else {
107return fn(p, arg);
108}
109}
110
111void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
112cb_iter fn, void *arg)
113{
114struct cb_node *p = t->root;
115struct cb_node *top = p;
116size_t i = 0;
117
118if (!p) return; /* empty tree */
119
120/* Walk tree, maintaining top pointer */
121while (1 & (uintptr_t)p) {
122struct cb_node *q = cb_node_of(p);
123uint8_t c = q->byte < klen ? kpfx[q->byte] : 0;
124size_t direction = (1 + (q->otherbits | c)) >> 8;
125
126p = q->child[direction];
127if (q->byte < klen)
128top = p;
129}
130
131for (i = 0; i < klen; i++) {
132if (p->k[i] != kpfx[i])
133return; /* "best" match failed */
134}
135cb_descend(top, fn, arg);
136}
137