/src/haproxy/include/import/cebtree-prv.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Compact Elastic Binary Trees - internal functions and types |
3 | | * |
4 | | * Copyright (C) 2014-2024 Willy Tarreau - w@1wt.eu |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining |
7 | | * a copy of this software and associated documentation files (the |
8 | | * "Software"), to deal in the Software without restriction, including |
9 | | * without limitation the rights to use, copy, modify, merge, publish, |
10 | | * distribute, sublicense, and/or sell copies of the Software, and to |
11 | | * permit persons to whom the Software is furnished to do so, subject to |
12 | | * the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be |
15 | | * included in all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
18 | | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
19 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
20 | | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
21 | | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
22 | | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
23 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
24 | | * OTHER DEALINGS IN THE SOFTWARE. |
25 | | */ |
26 | | |
27 | | /* This file MUST NOT be included by public code, it contains macros, enums |
28 | | * with short names and function definitions that may clash with user code. |
29 | | * It may only be included by the respective types' C files. |
30 | | */ |
31 | | |
32 | | /* |
33 | | * These trees are optimized for adding the minimalest overhead to the stored |
34 | | * data. This version uses the node's pointer as the key, for the purpose of |
35 | | * quickly finding its neighbours. |
36 | | * |
37 | | * A few properties : |
38 | | * - the xor between two branches of a node cannot be zero unless the two |
39 | | * branches are duplicate keys |
40 | | * - the xor between two nodes has *at least* the split bit set, possibly more |
41 | | * - the split bit is always strictly smaller for a node than for its parent, |
42 | | * which implies that the xor between the keys of the lowest level node is |
43 | | * always smaller than the xor between a higher level node. Hence the xor |
44 | | * between the branches of a regular leaf is always strictly larger than the |
45 | | * xor of its parent node's branches if this node is different, since the |
46 | | * leaf is associated with a higher level node which has at least one higher |
47 | | * level branch. The first leaf doesn't validate this but is handled by the |
48 | | * rules below. |
49 | | * - during the descent, the node corresponding to a leaf is always visited |
50 | | * before the leaf, unless it's the first inserted, nodeless leaf. |
51 | | * - the first key is the only one without any node, and it has both its |
52 | | * branches pointing to itself during insertion to detect it (i.e. xor==0). |
53 | | * - a leaf is always present as a node on the path from the root, except for |
54 | | * the inserted first key which has no node, and is recognizable by its two |
55 | | * branches pointing to itself. |
56 | | * - a consequence of the rules above is that a non-first leaf appearing below |
57 | | * a node will necessarily have an associated node with a split bit equal to |
58 | | * or greater than the node's split bit. |
59 | | * - another consequence is that below a node, the split bits are different for |
60 | | * each branches since both of them are already present above the node, thus |
61 | | * at different levels, so their respective XOR values will be different. |
62 | | * - since all nodes in a given path have a different split bit, if a leaf has |
63 | | * the same split bit as its parent node, it is necessary its associated leaf |
64 | | * |
65 | | * When descending along the tree, it is possible to know that a search key is |
66 | | * not present, because its XOR with both of the branches is strictly higher |
67 | | * than the inter-branch XOR. The reason is simple : the inter-branch XOR will |
68 | | * have its highest bit set indicating the split bit. Since it's the bit that |
69 | | * differs between the two branches, the key cannot have it both set and |
70 | | * cleared when comparing to the branch values. So xoring the key with both |
71 | | * branches will emit a higher bit only when the key's bit differs from both |
72 | | * branches' similar bit. Thus, the following equation : |
73 | | * (XOR(key, L) > XOR(L, R)) && (XOR(key, R) > XOR(L, R)) |
74 | | * is only true when the key should be placed above that node. Since the key |
75 | | * has a higher bit which differs from the node, either it has it set and the |
76 | | * node has it clear (same for both branches), or it has it clear and the node |
77 | | * has it set for both branches. For this reason it's enough to compare the key |
78 | | * with any node when the equation above is true, to know if it ought to be |
79 | | * present on the left or on the right side. This is useful for insertion and |
80 | | * for range lookups. |
81 | | */ |
82 | | |
83 | | #ifndef _CEBTREE_PRV_H |
84 | | #define _CEBTREE_PRV_H |
85 | | |
86 | | #include <inttypes.h> |
87 | | #include <string.h> |
88 | | #include "cebtree.h" |
89 | | |
90 | | /* If DEBUG is set, we'll print additional debugging info during the descent */ |
91 | | #ifdef DEBUG |
92 | | #define CEBDBG(x, ...) fprintf(stderr, x, ##__VA_ARGS__) |
93 | | #else |
94 | | #define CEBDBG(x, ...) do { } while (0) |
95 | | #endif |
96 | | |
97 | | /* These macros are used by upper level files to create two variants of their |
98 | | * exported functions: |
99 | | * - one which uses sizeof(struct ceb_node) as the key offset, for nodes with |
100 | | * adjacent keys ; these ones are named <pfx><sfx>(root, ...) |
101 | | * - one with an explicit key offset passed by the caller right after the |
102 | | * root. |
103 | | * Both rely on a forced inline version with a body that immediately follows |
104 | | * the declaration, so that the declaration looks like a single decorated |
105 | | * function while 2 are built in practice. There are variants for the basic one |
106 | | * with 0, 1 and 2 extra arguments after the root. The root and the key offset |
107 | | * are always the first two arguments, and the key offset never appears in the |
108 | | * first variant, it's always replaced by sizeof(struct ceb_node) in the calls |
109 | | * to the inline version. |
110 | | */ |
111 | | #define CEB_FDECL2(type, pfx, sfx, type1, arg1, type2, arg2) \ |
112 | | static inline __attribute__((always_inline)) \ |
113 | | type _##pfx##sfx(type1 arg1, type2 arg2); \ |
114 | 0 | type pfx##sfx(type1 arg1) { \ |
115 | 0 | return _##pfx##sfx(arg1, sizeof(struct ceb_node)); \ |
116 | 0 | } \ Unexecuted instantiation: cebu64_first Unexecuted instantiation: cebu64_last Unexecuted instantiation: cebus_first Unexecuted instantiation: cebus_last |
117 | 0 | type pfx##_ofs##sfx(type1 arg1, type2 arg2) { \ |
118 | 0 | return _##pfx##sfx(arg1, arg2); \ |
119 | 0 | } \ Unexecuted instantiation: cebu64_ofs_first Unexecuted instantiation: cebu64_ofs_last Unexecuted instantiation: cebus_ofs_first Unexecuted instantiation: cebus_ofs_last |
120 | | static inline __attribute__((always_inline)) \ |
121 | | type _##pfx##sfx(type1 arg1, type2 arg2) |
122 | | /* function body follows */ |
123 | | |
124 | | #define CEB_FDECL3(type, pfx, sfx, type1, arg1, type2, arg2, type3, arg3) \ |
125 | | static inline __attribute__((always_inline)) \ |
126 | | type _##pfx##sfx(type1 arg1, type2 arg2, type3 arg3); \ |
127 | 0 | type pfx##sfx(type1 arg1, type3 arg3) { \ |
128 | 0 | return _##pfx##sfx(arg1, sizeof(struct ceb_node), arg3); \ |
129 | 0 | } \ Unexecuted instantiation: cebu64_insert Unexecuted instantiation: cebu64_lookup Unexecuted instantiation: cebu64_lookup_le Unexecuted instantiation: cebu64_lookup_lt Unexecuted instantiation: cebu64_lookup_ge Unexecuted instantiation: cebu64_lookup_gt Unexecuted instantiation: cebu64_next Unexecuted instantiation: cebu64_prev Unexecuted instantiation: cebu64_delete Unexecuted instantiation: cebu64_pick Unexecuted instantiation: cebus_insert Unexecuted instantiation: cebus_lookup Unexecuted instantiation: cebus_lookup_le Unexecuted instantiation: cebus_lookup_lt Unexecuted instantiation: cebus_lookup_ge Unexecuted instantiation: cebus_lookup_gt Unexecuted instantiation: cebus_next Unexecuted instantiation: cebus_prev Unexecuted instantiation: cebus_delete Unexecuted instantiation: cebus_pick |
130 | 0 | type pfx##_ofs##sfx(type1 arg1, type2 arg2, type3 arg3) { \ |
131 | 0 | return _##pfx##sfx(arg1, arg2, arg3); \ |
132 | 0 | } \ Unexecuted instantiation: cebu64_ofs_insert Unexecuted instantiation: cebu64_ofs_lookup Unexecuted instantiation: cebu64_ofs_lookup_le Unexecuted instantiation: cebu64_ofs_lookup_lt Unexecuted instantiation: cebu64_ofs_lookup_ge Unexecuted instantiation: cebu64_ofs_lookup_gt Unexecuted instantiation: cebu64_ofs_next Unexecuted instantiation: cebu64_ofs_prev Unexecuted instantiation: cebu64_ofs_delete Unexecuted instantiation: cebu64_ofs_pick Unexecuted instantiation: cebus_ofs_insert Unexecuted instantiation: cebus_ofs_lookup Unexecuted instantiation: cebus_ofs_lookup_le Unexecuted instantiation: cebus_ofs_lookup_lt Unexecuted instantiation: cebus_ofs_lookup_ge Unexecuted instantiation: cebus_ofs_lookup_gt Unexecuted instantiation: cebus_ofs_next Unexecuted instantiation: cebus_ofs_prev Unexecuted instantiation: cebus_ofs_delete Unexecuted instantiation: cebus_ofs_pick |
133 | | static inline __attribute__((always_inline)) \ |
134 | | type _##pfx##sfx(type1 arg1, type2 arg2, type3 arg3) |
135 | | /* function body follows */ |
136 | | |
137 | | #define CEB_FDECL4(type, pfx, sfx, type1, arg1, type2, arg2, type3, arg3, type4, arg4) \ |
138 | | static inline __attribute__((always_inline)) \ |
139 | | type _##pfx##sfx(type1 arg1, type2 arg2, type3 arg3, type4 arg4); \ |
140 | 0 | type pfx##sfx(type1 arg1, type3 arg3, type4 arg4) { \ |
141 | 0 | return _##pfx##sfx(arg1, sizeof(struct ceb_node), arg3, arg4); \ |
142 | 0 | } \ Unexecuted instantiation: cebu64_default_dump Unexecuted instantiation: cebus_default_dump |
143 | 0 | type pfx##_ofs##sfx(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ |
144 | 0 | return _##pfx##sfx(arg1, arg2, arg3, arg4); \ |
145 | 0 | } \ Unexecuted instantiation: cebu64_ofs_default_dump Unexecuted instantiation: cebus_ofs_default_dump |
146 | | static inline __attribute__((always_inline)) \ |
147 | | type _##pfx##sfx(type1 arg1, type2 arg2, type3 arg3, type4 arg4) |
148 | | /* function body follows */ |
149 | | |
150 | | /* tree walk method: key, left, right */ |
151 | | enum ceb_walk_meth { |
152 | | CEB_WM_FST, /* look up "first" (walk left only) */ |
153 | | CEB_WM_NXT, /* look up "next" (walk right once then left) */ |
154 | | CEB_WM_PRV, /* look up "prev" (walk left once then right) */ |
155 | | CEB_WM_LST, /* look up "last" (walk right only) */ |
156 | | /* all methods from CEB_WM_KEQ and above do have a key */ |
157 | | CEB_WM_KEQ, /* look up the node equal to the key */ |
158 | | CEB_WM_KGE, /* look up the node greater than or equal to the key */ |
159 | | CEB_WM_KGT, /* look up the node greater than the key */ |
160 | | CEB_WM_KLE, /* look up the node lower than or equal to the key */ |
161 | | CEB_WM_KLT, /* look up the node lower than the key */ |
162 | | CEB_WM_KNX, /* look up the node's key first, then find the next */ |
163 | | CEB_WM_KPR, /* look up the node's key first, then find the prev */ |
164 | | }; |
165 | | |
166 | | enum ceb_key_type { |
167 | | CEB_KT_ADDR, /* the key is the node's address */ |
168 | | CEB_KT_U32, /* 32-bit unsigned word in key_u32 */ |
169 | | CEB_KT_U64, /* 64-bit unsigned word in key_u64 */ |
170 | | CEB_KT_MB, /* fixed size memory block in (key_u64,key_ptr), direct storage */ |
171 | | CEB_KT_IM, /* fixed size memory block in (key_u64,key_ptr), indirect storage */ |
172 | | CEB_KT_ST, /* NUL-terminated string in key_ptr, direct storage */ |
173 | | CEB_KT_IS, /* NUL-terminated string in key_ptr, indirect storage */ |
174 | | }; |
175 | | |
176 | | union ceb_key_storage { |
177 | | uint32_t u32; |
178 | | uint64_t u64; |
179 | | unsigned long ul; |
180 | | unsigned char mb[0]; |
181 | | unsigned char str[0]; |
182 | | unsigned char *ptr; /* for CEB_KT_IS */ |
183 | | }; |
184 | | |
185 | | /* returns the ceb_key_storage pointer for node <n> and offset <o> */ |
186 | 0 | #define NODEK(n, o) ((union ceb_key_storage*)(((char *)(n)) + (o))) |
187 | | |
188 | | /* Returns the xor (or common length) between the two sides <l> and <r> if both |
189 | | * are non-null, otherwise between the first non-null one and the value in the |
190 | | * associate key. As a reminder, memory blocks place their length in key_u64. |
191 | | * This is only intended for internal use, essentially for debugging. |
192 | | * |
193 | | * <kofs> contains the offset between the key and the node's base. When simply |
194 | | * adjacent, this would just be sizeof(ceb_node). |
195 | | */ |
196 | | __attribute__((unused)) |
197 | | static inline uint64_t _xor_branches(ptrdiff_t kofs, enum ceb_key_type key_type, uint32_t key_u32, |
198 | | uint64_t key_u64, const void *key_ptr, |
199 | | const struct ceb_node *l, |
200 | | const struct ceb_node *r) |
201 | 0 | { |
202 | 0 | if (l && r) { |
203 | 0 | if (key_type == CEB_KT_MB) |
204 | 0 | return equal_bits(NODEK(l, kofs)->mb, NODEK(r, kofs)->mb, 0, key_u64 << 3); |
205 | 0 | else if (key_type == CEB_KT_IM) |
206 | 0 | return equal_bits(NODEK(l, kofs)->mb, NODEK(r, kofs)->ptr, 0, key_u64 << 3); |
207 | 0 | else if (key_type == CEB_KT_ST) |
208 | 0 | return string_equal_bits(NODEK(l, kofs)->str, NODEK(r, kofs)->str, 0); |
209 | 0 | else if (key_type == CEB_KT_IS) |
210 | 0 | return string_equal_bits(NODEK(l, kofs)->ptr, NODEK(r, kofs)->ptr, 0); |
211 | 0 | else if (key_type == CEB_KT_U64) |
212 | 0 | return NODEK(l, kofs)->u64 ^ NODEK(r, kofs)->u64; |
213 | 0 | else if (key_type == CEB_KT_U32) |
214 | 0 | return NODEK(l, kofs)->u32 ^ NODEK(r, kofs)->u32; |
215 | 0 | else if (key_type == CEB_KT_ADDR) |
216 | 0 | return ((uintptr_t)l ^ (uintptr_t)r); |
217 | 0 | else |
218 | 0 | return 0; |
219 | 0 | } |
220 | | |
221 | 0 | if (!l) |
222 | 0 | l = r; |
223 | |
|
224 | 0 | if (key_type == CEB_KT_MB) |
225 | 0 | return equal_bits(key_ptr, NODEK(l, kofs)->mb, 0, key_u64 << 3); |
226 | 0 | else if (key_type == CEB_KT_IM) |
227 | 0 | return equal_bits(key_ptr, NODEK(l, kofs)->ptr, 0, key_u64 << 3); |
228 | 0 | else if (key_type == CEB_KT_ST) |
229 | 0 | return string_equal_bits(key_ptr, NODEK(l, kofs)->str, 0); |
230 | 0 | else if (key_type == CEB_KT_IS) |
231 | 0 | return string_equal_bits(key_ptr, NODEK(l, kofs)->ptr, 0); |
232 | 0 | else if (key_type == CEB_KT_U64) |
233 | 0 | return key_u64 ^ NODEK(l, kofs)->u64; |
234 | 0 | else if (key_type == CEB_KT_U32) |
235 | 0 | return key_u32 ^ NODEK(l, kofs)->u32; |
236 | 0 | else if (key_type == CEB_KT_ADDR) |
237 | 0 | return ((uintptr_t)key_ptr ^ (uintptr_t)r); |
238 | 0 | else |
239 | 0 | return 0; |
240 | 0 | } Unexecuted instantiation: cebu64_tree.c:_xor_branches Unexecuted instantiation: cebus_tree.c:_xor_branches |
241 | | |
242 | | #ifdef DEBUG |
243 | | __attribute__((unused)) |
244 | | static void dbg(int line, |
245 | | const char *pfx, |
246 | | enum ceb_walk_meth meth, |
247 | | ptrdiff_t kofs, |
248 | | enum ceb_key_type key_type, |
249 | | struct ceb_node * const *root, |
250 | | const struct ceb_node *p, |
251 | | uint32_t key_u32, |
252 | | uint64_t key_u64, |
253 | | const void *key_ptr, |
254 | | uint32_t px32, |
255 | | uint64_t px64, |
256 | | size_t plen) |
257 | | { |
258 | | const char *meths[] = { |
259 | | [CEB_WM_FST] = "FST", |
260 | | [CEB_WM_NXT] = "NXT", |
261 | | [CEB_WM_PRV] = "PRV", |
262 | | [CEB_WM_LST] = "LST", |
263 | | [CEB_WM_KEQ] = "KEQ", |
264 | | [CEB_WM_KGE] = "KGE", |
265 | | [CEB_WM_KGT] = "KGT", |
266 | | [CEB_WM_KLE] = "KLE", |
267 | | [CEB_WM_KLT] = "KLT", |
268 | | [CEB_WM_KNX] = "KNX", |
269 | | [CEB_WM_KPR] = "KPR", |
270 | | }; |
271 | | const char *ktypes[] = { |
272 | | [CEB_KT_ADDR] = "ADDR", |
273 | | [CEB_KT_U32] = "U32", |
274 | | [CEB_KT_U64] = "U64", |
275 | | [CEB_KT_MB] = "MB", |
276 | | [CEB_KT_IM] = "IM", |
277 | | [CEB_KT_ST] = "ST", |
278 | | [CEB_KT_IS] = "IS", |
279 | | }; |
280 | | const char *kstr __attribute__((unused)) = ktypes[key_type]; |
281 | | const char *mstr __attribute__((unused)) = meths[meth]; |
282 | | long long nlen __attribute__((unused)) = 0; |
283 | | long long llen __attribute__((unused)) = 0; |
284 | | long long rlen __attribute__((unused)) = 0; |
285 | | long long xlen __attribute__((unused)) = 0; |
286 | | |
287 | | if (p) |
288 | | nlen = _xor_branches(kofs, key_type, key_u32, key_u64, key_ptr, p, NULL); |
289 | | |
290 | | if (p && p->b[0]) |
291 | | llen = _xor_branches(kofs, key_type, key_u32, key_u64, key_ptr, p->b[0], NULL); |
292 | | |
293 | | if (p && p->b[1]) |
294 | | rlen = _xor_branches(kofs, key_type, key_u32, key_u64, key_ptr, NULL, p->b[1]); |
295 | | |
296 | | if (p && p->b[0] && p->b[1]) |
297 | | xlen = _xor_branches(kofs, key_type, key_u32, key_u64, key_ptr, p->b[0], p->b[1]); |
298 | | |
299 | | switch (key_type) { |
300 | | case CEB_KT_U32: |
301 | | CEBDBG("%04d (%8s) m=%s.%s key=%#x root=%p pxor=%#x p=%p,%#x(^%#llx) l=%p,%#x(^%#llx) r=%p,%#x(^%#llx) l^r=%#llx\n", |
302 | | line, pfx, kstr, mstr, key_u32, root, px32, |
303 | | p, p ? NODEK(p, kofs)->u32 : 0, nlen, |
304 | | p ? p->b[0] : NULL, p ? NODEK(p->b[0], kofs)->u32 : 0, llen, |
305 | | p ? p->b[1] : NULL, p ? NODEK(p->b[1], kofs)->u32 : 0, rlen, |
306 | | xlen); |
307 | | break; |
308 | | case CEB_KT_U64: |
309 | | CEBDBG("%04d (%8s) m=%s.%s key=%#llx root=%p pxor=%#llx p=%p,%#llx(^%#llx) l=%p,%#llx(^%#llx) r=%p,%#llx(^%#llx) l^r=%#llx\n", |
310 | | line, pfx, kstr, mstr, (long long)key_u64, root, (long long)px64, |
311 | | p, (long long)(p ? NODEK(p, kofs)->u64 : 0), nlen, |
312 | | p ? p->b[0] : NULL, (long long)(p ? NODEK(p->b[0], kofs)->u64 : 0), llen, |
313 | | p ? p->b[1] : NULL, (long long)(p ? NODEK(p->b[1], kofs)->u64 : 0), rlen, |
314 | | xlen); |
315 | | break; |
316 | | case CEB_KT_MB: |
317 | | CEBDBG("%04d (%8s) m=%s.%s key=%p root=%p plen=%ld p=%p,%p(^%llu) l=%p,%p(^%llu) r=%p,%p(^%llu) l^r=%llu\n", |
318 | | line, pfx, kstr, mstr, key_ptr, root, (long)plen, |
319 | | p, p ? NODEK(p, kofs)->mb : 0, nlen, |
320 | | p ? p->b[0] : NULL, p ? NODEK(p->b[0], kofs)->mb : 0, llen, |
321 | | p ? p->b[1] : NULL, p ? NODEK(p->b[1], kofs)->mb : 0, rlen, |
322 | | xlen); |
323 | | break; |
324 | | case CEB_KT_IM: |
325 | | CEBDBG("%04d (%8s) m=%s.%s key=%p root=%p plen=%ld p=%p,%p(^%llu) l=%p,%p(^%llu) r=%p,%p(^%llu) l^r=%llu\n", |
326 | | line, pfx, kstr, mstr, key_ptr, root, (long)plen, |
327 | | p, p ? NODEK(p, kofs)->ptr : 0, nlen, |
328 | | p ? p->b[0] : NULL, p ? NODEK(p->b[0], kofs)->ptr : 0, llen, |
329 | | p ? p->b[1] : NULL, p ? NODEK(p->b[1], kofs)->ptr : 0, rlen, |
330 | | xlen); |
331 | | break; |
332 | | case CEB_KT_ST: |
333 | | CEBDBG("%04d (%8s) m=%s.%s key='%s' root=%p plen=%ld p=%p,%s(^%llu) l=%p,%s(^%llu) r=%p,%s(^%llu) l^r=%llu\n", |
334 | | line, pfx, kstr, mstr, key_ptr ? (const char *)key_ptr : "", root, (long)plen, |
335 | | p, p ? (const char *)NODEK(p, kofs)->str : "-", nlen, |
336 | | p ? p->b[0] : NULL, p ? (const char *)NODEK(p->b[0], kofs)->str : "-", llen, |
337 | | p ? p->b[1] : NULL, p ? (const char *)NODEK(p->b[1], kofs)->str : "-", rlen, |
338 | | xlen); |
339 | | break; |
340 | | case CEB_KT_IS: |
341 | | CEBDBG("%04d (%8s) m=%s.%s key='%s' root=%p plen=%ld p=%p,%s(^%llu) l=%p,%s(^%llu) r=%p,%s(^%llu) l^r=%llu\n", |
342 | | line, pfx, kstr, mstr, key_ptr ? (const char *)key_ptr : "", root, (long)plen, |
343 | | p, p ? (const char *)NODEK(p, kofs)->ptr : "-", nlen, |
344 | | p ? p->b[0] : NULL, p ? (const char *)NODEK(p->b[0], kofs)->ptr : "-", llen, |
345 | | p ? p->b[1] : NULL, p ? (const char *)NODEK(p->b[1], kofs)->ptr : "-", rlen, |
346 | | xlen); |
347 | | break; |
348 | | case CEB_KT_ADDR: |
349 | | /* key type is the node's address */ |
350 | | CEBDBG("%04d (%8s) m=%s.%s key=%#llx root=%p pxor=%#llx p=%p,%#llx(^%#llx) l=%p,%#llx(^%#llx) r=%p,%#llx(^%#llx) l^r=%#llx\n", |
351 | | line, pfx, kstr, mstr, (long long)(uintptr_t)key_ptr, root, (long long)px64, |
352 | | p, (long long)(uintptr_t)p, nlen, |
353 | | p ? p->b[0] : NULL, p ? (long long)(uintptr_t)p->b[0] : 0, llen, |
354 | | p ? p->b[1] : NULL, p ? (long long)(uintptr_t)p->b[1] : 0, rlen, |
355 | | xlen); |
356 | | } |
357 | | } |
358 | | #else |
359 | 0 | #define dbg(...) do { } while (0) |
360 | | #endif |
361 | | |
362 | | /* Generic tree descent function. It must absolutely be inlined so that the |
363 | | * compiler can eliminate the tests related to the various return pointers, |
364 | | * which must either point to a local variable in the caller, or be NULL. |
365 | | * It must not be called with an empty tree, it's the caller business to |
366 | | * deal with this special case. It returns in ret_root the location of the |
367 | | * pointer to the leaf (i.e. where we have to insert ourselves). The integer |
368 | | * pointed to by ret_nside will contain the side the leaf should occupy at |
369 | | * its own node, with the sibling being *ret_root. Note that keys for fixed- |
370 | | * size arrays are passed in key_ptr with their length in key_u64. For keyless |
371 | | * nodes whose address serves as the key, the pointer needs to be passed in |
372 | | * key_ptr, and pxor64 will be used internally. |
373 | | */ |
374 | | static inline __attribute__((always_inline)) |
375 | | struct ceb_node *_cebu_descend(struct ceb_node **root, |
376 | | enum ceb_walk_meth meth, |
377 | | ptrdiff_t kofs, |
378 | | enum ceb_key_type key_type, |
379 | | uint32_t key_u32, |
380 | | uint64_t key_u64, |
381 | | const void *key_ptr, |
382 | | int *ret_nside, |
383 | | struct ceb_node ***ret_root, |
384 | | struct ceb_node **ret_lparent, |
385 | | int *ret_lpside, |
386 | | struct ceb_node **ret_nparent, |
387 | | int *ret_npside, |
388 | | struct ceb_node **ret_gparent, |
389 | | int *ret_gpside, |
390 | | struct ceb_node **ret_back) |
391 | 0 | { |
392 | | #if !defined(__OPTIMIZE__) && __GNUC_PREREQ__(12, 0) |
393 | | /* Avoid a bogus warning with gcc 12 and above: it warns about negative |
394 | | * memcmp() length in non-existing code paths at -O0, as reported here: |
395 | | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114622 |
396 | | */ |
397 | | #pragma GCC diagnostic push |
398 | | #pragma GCC diagnostic ignored "-Wstringop-overread" |
399 | | #endif |
400 | 0 | struct ceb_node *p; |
401 | 0 | union ceb_key_storage *l, *r, *k; |
402 | 0 | struct ceb_node *gparent = NULL; |
403 | 0 | struct ceb_node *nparent = NULL; |
404 | 0 | struct ceb_node *bnode = NULL; |
405 | 0 | struct ceb_node *lparent; |
406 | 0 | uint32_t pxor32 = ~0U; // previous xor between branches |
407 | 0 | uint64_t pxor64 = ~0ULL; // previous xor between branches |
408 | 0 | int gpside = 0; // side on the grand parent |
409 | 0 | int npside = 0; // side on the node's parent |
410 | 0 | long lpside = 0; // side on the leaf's parent |
411 | 0 | long brside = 0; // branch side when descending |
412 | 0 | size_t llen = 0; // left vs key matching length |
413 | 0 | size_t rlen = 0; // right vs key matching length |
414 | 0 | size_t plen = 0; // previous common len between branches |
415 | 0 | int found = 0; // key was found (saves an extra strcmp for arrays) |
416 | |
|
417 | 0 | dbg(__LINE__, "_enter__", meth, kofs, key_type, root, NULL, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
418 | | |
419 | | /* the parent will be the (possibly virtual) node so that |
420 | | * &lparent->l == root. |
421 | | */ |
422 | 0 | lparent = container_of(root, struct ceb_node, b[0]); |
423 | 0 | gparent = nparent = lparent; |
424 | | |
425 | | /* for key-less descents we need to set the initial branch to take */ |
426 | 0 | switch (meth) { |
427 | 0 | case CEB_WM_NXT: |
428 | 0 | case CEB_WM_LST: |
429 | 0 | brside = 1; // start right for next/last |
430 | 0 | break; |
431 | 0 | case CEB_WM_FST: |
432 | 0 | case CEB_WM_PRV: |
433 | 0 | default: |
434 | 0 | brside = 0; // start left for first/prev |
435 | 0 | break; |
436 | 0 | } |
437 | | |
438 | | /* the previous xor is initialized to the largest possible inter-branch |
439 | | * value so that it can never match on the first test as we want to use |
440 | | * it to detect a leaf vs node. That's achieved with plen==0 for arrays |
441 | | * and pxorXX==~0 for scalars. |
442 | | */ |
443 | 0 | while (1) { |
444 | 0 | p = *root; |
445 | | |
446 | | /* Tests have shown that for write-intensive workloads (many |
447 | | * insertions/deletion), prefetching for reads is counter |
448 | | * productive (-10% perf) but that prefetching only the next |
449 | | * nodes for writes when deleting can yield around 3% extra |
450 | | * boost. |
451 | | */ |
452 | 0 | if (ret_lpside) { |
453 | | /* this is a deletion, prefetch for writes */ |
454 | 0 | __builtin_prefetch(p->b[0], 1); |
455 | 0 | __builtin_prefetch(p->b[1], 1); |
456 | 0 | } |
457 | | |
458 | | /* neither pointer is tagged */ |
459 | 0 | k = NODEK(p, kofs); |
460 | 0 | l = NODEK(p->b[0], kofs); |
461 | 0 | r = NODEK(p->b[1], kofs); |
462 | |
|
463 | 0 | dbg(__LINE__, "newp", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
464 | | |
465 | | /* two equal pointers identifies the nodeless leaf. */ |
466 | 0 | if (l == r) { |
467 | 0 | dbg(__LINE__, "l==r", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
468 | 0 | break; |
469 | 0 | } |
470 | | |
471 | | /* In the following block, we're dealing with type-specific |
472 | | * operations which follow the same construct for each type: |
473 | | * 1) calculate the new side for key lookups (otherwise keep |
474 | | * the current side, e.g. for first/last). Doing it early |
475 | | * allows the CPU to more easily predict next branches and |
476 | | * is faster by ~10%. For complex bits we keep the length |
477 | | * of identical bits instead of xor. We can also xor lkey |
478 | | * and rkey with key and use it everywhere later but it |
479 | | * doesn't seem to bring anything. |
480 | | * |
481 | | * 2) calculate the xor between the two sides to figure the |
482 | | * split bit position. If the new split bit is before the |
483 | | * previous one, we've reached a leaf: each leaf we visit |
484 | | * had its node part already visited. The only way to |
485 | | * distinguish them is that the inter-branch xor of the |
486 | | * leaf will be the node's one, and will necessarily be |
487 | | * larger than the previous node's xor if the node is |
488 | | * above (we've already checked for direct descendent |
489 | | * below). Said differently, if an inter-branch xor is |
490 | | * strictly larger than the previous one, it necessarily |
491 | | * is the one of an upper node, so what we're seeing |
492 | | * cannot be the node, hence it's the leaf. The case where |
493 | | * they're equal was already dealt with by the test at the |
494 | | * end of the loop (node points to self). For scalar keys, |
495 | | * we directly store the last xor value in pxorXX. For |
496 | | * arrays and strings, instead we store the previous equal |
497 | | * length. |
498 | | * |
499 | | * 3) for lookups, check if the looked key still has a chance |
500 | | * to be below: if it has a xor with both branches that is |
501 | | * larger than the xor between them, it cannot be there, |
502 | | * since it means that it differs from these branches by |
503 | | * at least one bit that's higher than the split bit, |
504 | | * hence not common to these branches. In such cases: |
505 | | * - if we're just doing a lookup, the key is not found |
506 | | * and we fail. |
507 | | * - if we are inserting, we must stop here and we have |
508 | | * the guarantee to be above a node. |
509 | | * - if we're deleting, it could be the key we were |
510 | | * looking for so we have to check for it as long as |
511 | | * it's still possible to keep a copy of the node's |
512 | | * parent. <found> is set int this case for expensive |
513 | | * types. |
514 | | */ |
515 | | |
516 | 0 | if (key_type == CEB_KT_U32) { |
517 | 0 | uint32_t xor32; // left vs right branch xor |
518 | 0 | uint32_t kl, kr; |
519 | |
|
520 | 0 | kl = l->u32; kr = r->u32; |
521 | 0 | xor32 = kl ^ kr; |
522 | |
|
523 | 0 | if (xor32 > pxor32) { // test using 2 4 6 4 |
524 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
525 | 0 | break; |
526 | 0 | } |
527 | | |
528 | 0 | if (meth >= CEB_WM_KEQ) { |
529 | | /* "found" is not used here */ |
530 | 0 | kl ^= key_u32; kr ^= key_u32; |
531 | 0 | brside = kl >= kr; |
532 | | |
533 | | /* let's stop if our key is not there */ |
534 | |
|
535 | 0 | if (kl > xor32 && kr > xor32) { |
536 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
537 | 0 | break; |
538 | 0 | } |
539 | | |
540 | 0 | if (ret_npside || ret_nparent) { |
541 | 0 | if (key_u32 == k->u32) { |
542 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
543 | 0 | nparent = lparent; |
544 | 0 | npside = lpside; |
545 | 0 | } |
546 | 0 | } |
547 | 0 | } |
548 | 0 | pxor32 = xor32; |
549 | 0 | } |
550 | 0 | else if (key_type == CEB_KT_U64) { |
551 | 0 | uint64_t xor64; // left vs right branch xor |
552 | 0 | uint64_t kl, kr; |
553 | |
|
554 | 0 | kl = l->u64; kr = r->u64; |
555 | 0 | xor64 = kl ^ kr; |
556 | |
|
557 | 0 | if (xor64 > pxor64) { // test using 2 4 6 4 |
558 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
559 | 0 | break; |
560 | 0 | } |
561 | | |
562 | 0 | if (meth >= CEB_WM_KEQ) { |
563 | | /* "found" is not used here */ |
564 | 0 | kl ^= key_u64; kr ^= key_u64; |
565 | 0 | brside = kl >= kr; |
566 | | |
567 | | /* let's stop if our key is not there */ |
568 | |
|
569 | 0 | if (kl > xor64 && kr > xor64) { |
570 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
571 | 0 | break; |
572 | 0 | } |
573 | | |
574 | 0 | if (ret_npside || ret_nparent) { |
575 | 0 | if (key_u64 == k->u64) { |
576 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
577 | 0 | nparent = lparent; |
578 | 0 | npside = lpside; |
579 | 0 | } |
580 | 0 | } |
581 | 0 | } |
582 | 0 | pxor64 = xor64; |
583 | 0 | } |
584 | 0 | else if (key_type == CEB_KT_MB) { |
585 | 0 | size_t xlen = 0; // left vs right matching length |
586 | |
|
587 | 0 | if (meth >= CEB_WM_KEQ) { |
588 | | /* measure identical lengths */ |
589 | 0 | llen = equal_bits(key_ptr, l->mb, 0, key_u64 << 3); |
590 | 0 | rlen = equal_bits(key_ptr, r->mb, 0, key_u64 << 3); |
591 | 0 | brside = llen <= rlen; |
592 | 0 | if (llen == rlen && (uint64_t)llen == key_u64 << 3) |
593 | 0 | found = 1; |
594 | 0 | } |
595 | |
|
596 | 0 | xlen = equal_bits(l->mb, r->mb, 0, key_u64 << 3); |
597 | 0 | if (xlen < plen) { |
598 | | /* this is a leaf. E.g. triggered using 2 4 6 4 */ |
599 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
600 | 0 | break; |
601 | 0 | } |
602 | | |
603 | 0 | if (meth >= CEB_WM_KEQ) { |
604 | | /* let's stop if our key is not there */ |
605 | |
|
606 | 0 | if (llen < xlen && rlen < xlen) { |
607 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
608 | 0 | break; |
609 | 0 | } |
610 | | |
611 | 0 | if (ret_npside || ret_nparent) { // delete ? |
612 | 0 | size_t mlen = llen > rlen ? llen : rlen; |
613 | |
|
614 | 0 | if (mlen > xlen) |
615 | 0 | mlen = xlen; |
616 | |
|
617 | 0 | if ((uint64_t)xlen / 8 == key_u64 || memcmp(key_ptr + mlen / 8, k->mb + mlen / 8, key_u64 - mlen / 8) == 0) { |
618 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
619 | 0 | nparent = lparent; |
620 | 0 | npside = lpside; |
621 | 0 | found = 1; |
622 | 0 | } |
623 | 0 | } |
624 | 0 | } |
625 | 0 | plen = xlen; |
626 | 0 | } |
627 | 0 | else if (key_type == CEB_KT_IM) { |
628 | 0 | size_t xlen = 0; // left vs right matching length |
629 | |
|
630 | 0 | if (meth >= CEB_WM_KEQ) { |
631 | | /* measure identical lengths */ |
632 | 0 | llen = equal_bits(key_ptr, l->ptr, 0, key_u64 << 3); |
633 | 0 | rlen = equal_bits(key_ptr, r->ptr, 0, key_u64 << 3); |
634 | 0 | brside = llen <= rlen; |
635 | 0 | if (llen == rlen && (uint64_t)llen == key_u64 << 3) |
636 | 0 | found = 1; |
637 | 0 | } |
638 | |
|
639 | 0 | xlen = equal_bits(l->ptr, r->ptr, 0, key_u64 << 3); |
640 | 0 | if (xlen < plen) { |
641 | | /* this is a leaf. E.g. triggered using 2 4 6 4 */ |
642 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
643 | 0 | break; |
644 | 0 | } |
645 | | |
646 | 0 | if (meth >= CEB_WM_KEQ) { |
647 | | /* let's stop if our key is not there */ |
648 | |
|
649 | 0 | if (llen < xlen && rlen < xlen) { |
650 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
651 | 0 | break; |
652 | 0 | } |
653 | | |
654 | 0 | if (ret_npside || ret_nparent) { // delete ? |
655 | 0 | size_t mlen = llen > rlen ? llen : rlen; |
656 | |
|
657 | 0 | if (mlen > xlen) |
658 | 0 | mlen = xlen; |
659 | |
|
660 | 0 | if ((uint64_t)xlen / 8 == key_u64 || memcmp(key_ptr + mlen / 8, k->ptr + mlen / 8, key_u64 - mlen / 8) == 0) { |
661 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
662 | 0 | nparent = lparent; |
663 | 0 | npside = lpside; |
664 | 0 | found = 1; |
665 | 0 | } |
666 | 0 | } |
667 | 0 | } |
668 | 0 | plen = xlen; |
669 | 0 | } |
670 | 0 | else if (key_type == CEB_KT_ST) { |
671 | 0 | size_t xlen = 0; // left vs right matching length |
672 | |
|
673 | 0 | if (meth >= CEB_WM_KEQ) { |
674 | | /* Note that a negative length indicates an |
675 | | * equal value with the final zero reached, but |
676 | | * it is still needed to descend to find the |
677 | | * leaf. We take that negative length for an |
678 | | * infinite one, hence the uint cast. |
679 | | */ |
680 | 0 | llen = string_equal_bits(key_ptr, l->str, 0); |
681 | 0 | rlen = string_equal_bits(key_ptr, r->str, 0); |
682 | 0 | brside = (size_t)llen <= (size_t)rlen; |
683 | 0 | if ((ssize_t)llen < 0 || (ssize_t)rlen < 0) |
684 | 0 | found = 1; |
685 | 0 | } |
686 | |
|
687 | 0 | xlen = string_equal_bits(l->str, r->str, 0); |
688 | 0 | if (xlen < plen) { |
689 | | /* this is a leaf. E.g. triggered using 2 4 6 4 */ |
690 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
691 | 0 | break; |
692 | 0 | } |
693 | | |
694 | 0 | if (meth >= CEB_WM_KEQ) { |
695 | | /* let's stop if our key is not there */ |
696 | |
|
697 | 0 | if ((unsigned)llen < (unsigned)xlen && (unsigned)rlen < (unsigned)xlen) { |
698 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
699 | 0 | break; |
700 | 0 | } |
701 | | |
702 | 0 | if (ret_npside || ret_nparent) { // delete ? |
703 | 0 | size_t mlen = llen > rlen ? llen : rlen; |
704 | |
|
705 | 0 | if (mlen > xlen) |
706 | 0 | mlen = xlen; |
707 | |
|
708 | 0 | if (strcmp(key_ptr + mlen / 8, (const void *)k->str + mlen / 8) == 0) { |
709 | | /* strcmp() still needed. E.g. 1 2 3 4 10 11 4 3 2 1 10 11 fails otherwise */ |
710 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
711 | 0 | nparent = lparent; |
712 | 0 | npside = lpside; |
713 | 0 | found = 1; |
714 | 0 | } |
715 | 0 | } |
716 | 0 | } |
717 | 0 | plen = xlen; |
718 | 0 | } |
719 | 0 | else if (key_type == CEB_KT_IS) { |
720 | 0 | size_t xlen = 0; // left vs right matching length |
721 | |
|
722 | 0 | if (meth >= CEB_WM_KEQ) { |
723 | | /* Note that a negative length indicates an |
724 | | * equal value with the final zero reached, but |
725 | | * it is still needed to descend to find the |
726 | | * leaf. We take that negative length for an |
727 | | * infinite one, hence the uint cast. |
728 | | */ |
729 | 0 | llen = string_equal_bits(key_ptr, l->ptr, 0); |
730 | 0 | rlen = string_equal_bits(key_ptr, r->ptr, 0); |
731 | 0 | brside = (size_t)llen <= (size_t)rlen; |
732 | 0 | if ((ssize_t)llen < 0 || (ssize_t)rlen < 0) |
733 | 0 | found = 1; |
734 | 0 | } |
735 | |
|
736 | 0 | xlen = string_equal_bits(l->ptr, r->ptr, 0); |
737 | 0 | if (xlen < plen) { |
738 | | /* this is a leaf. E.g. triggered using 2 4 6 4 */ |
739 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
740 | 0 | break; |
741 | 0 | } |
742 | | |
743 | 0 | if (meth >= CEB_WM_KEQ) { |
744 | | /* let's stop if our key is not there */ |
745 | |
|
746 | 0 | if ((unsigned)llen < (unsigned)xlen && (unsigned)rlen < (unsigned)xlen) { |
747 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
748 | 0 | break; |
749 | 0 | } |
750 | | |
751 | 0 | if (ret_npside || ret_nparent) { // delete ? |
752 | 0 | size_t mlen = llen > rlen ? llen : rlen; |
753 | |
|
754 | 0 | if (mlen > xlen) |
755 | 0 | mlen = xlen; |
756 | |
|
757 | 0 | if (strcmp(key_ptr + mlen / 8, (const void *)k->ptr + mlen / 8) == 0) { |
758 | | /* strcmp() still needed. E.g. 1 2 3 4 10 11 4 3 2 1 10 11 fails otherwise */ |
759 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
760 | 0 | nparent = lparent; |
761 | 0 | npside = lpside; |
762 | 0 | found = 1; |
763 | 0 | } |
764 | 0 | } |
765 | 0 | } |
766 | 0 | plen = xlen; |
767 | 0 | } |
768 | 0 | else if (key_type == CEB_KT_ADDR) { |
769 | 0 | uintptr_t xoraddr; // left vs right branch xor |
770 | 0 | uintptr_t kl, kr; |
771 | |
|
772 | 0 | kl = (uintptr_t)l; kr = (uintptr_t)r; |
773 | 0 | xoraddr = kl ^ kr; |
774 | |
|
775 | 0 | if (xoraddr > (uintptr_t)pxor64) { // test using 2 4 6 4 |
776 | 0 | dbg(__LINE__, "xor>", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
777 | 0 | break; |
778 | 0 | } |
779 | | |
780 | 0 | if (meth >= CEB_WM_KEQ) { |
781 | | /* "found" is not used here */ |
782 | 0 | kl ^= (uintptr_t)key_ptr; kr ^= (uintptr_t)key_ptr; |
783 | 0 | brside = kl >= kr; |
784 | | |
785 | | /* let's stop if our key is not there */ |
786 | |
|
787 | 0 | if (kl > xoraddr && kr > xoraddr) { |
788 | 0 | dbg(__LINE__, "mismatch", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
789 | 0 | break; |
790 | 0 | } |
791 | | |
792 | 0 | if (ret_npside || ret_nparent) { |
793 | 0 | if ((uintptr_t)key_ptr == (uintptr_t)p) { |
794 | 0 | dbg(__LINE__, "equal", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
795 | 0 | nparent = lparent; |
796 | 0 | npside = lpside; |
797 | 0 | } |
798 | 0 | } |
799 | 0 | } |
800 | 0 | pxor64 = xoraddr; |
801 | 0 | } |
802 | | |
803 | | /* shift all copies by one */ |
804 | 0 | gparent = lparent; |
805 | 0 | gpside = lpside; |
806 | 0 | lparent = p; |
807 | 0 | lpside = brside; |
808 | 0 | if (brside) { |
809 | 0 | if (meth == CEB_WM_KPR || meth == CEB_WM_KLE || meth == CEB_WM_KLT) |
810 | 0 | bnode = p; |
811 | 0 | root = &p->b[1]; |
812 | | |
813 | | /* change branch for key-less walks */ |
814 | 0 | if (meth == CEB_WM_NXT) |
815 | 0 | brside = 0; |
816 | |
|
817 | 0 | dbg(__LINE__, "side1", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
818 | 0 | } |
819 | 0 | else { |
820 | 0 | if (meth == CEB_WM_KNX || meth == CEB_WM_KGE || meth == CEB_WM_KGT) |
821 | 0 | bnode = p; |
822 | 0 | root = &p->b[0]; |
823 | | |
824 | | /* change branch for key-less walks */ |
825 | 0 | if (meth == CEB_WM_PRV) |
826 | 0 | brside = 1; |
827 | |
|
828 | 0 | dbg(__LINE__, "side0", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
829 | 0 | } |
830 | |
|
831 | 0 | if (p == *root) { |
832 | | /* loops over itself, it's a leaf */ |
833 | 0 | dbg(__LINE__, "loop", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
834 | 0 | break; |
835 | 0 | } |
836 | 0 | } |
837 | | |
838 | | /* here we're on the closest node from the requested value. It may be |
839 | | * slightly lower (has a zero where we expected a one) or slightly |
840 | | * larger has a one where we expected a zero). Thus another check is |
841 | | * still deserved, depending on the matching method. |
842 | | */ |
843 | | |
844 | | /* if we've exited on an exact match after visiting a regular node |
845 | | * (i.e. not the nodeless leaf), we'll avoid checking the string again. |
846 | | * However if it doesn't match, we must make sure to compare from |
847 | | * within the key (which can be shorter than the ones already there), |
848 | | * so we restart the check from the longest of the two lengths, which |
849 | | * guarantees these bits exist. Test with "100", "10", "1" to see where |
850 | | * this is needed. |
851 | | */ |
852 | 0 | if ((key_type == CEB_KT_ST || key_type == CEB_KT_IS) && meth >= CEB_WM_KEQ && !found) |
853 | 0 | plen = (llen > rlen) ? llen : rlen; |
854 | | |
855 | | /* update the pointers needed for modifications (insert, delete) */ |
856 | 0 | if (ret_nside && meth >= CEB_WM_KEQ) { |
857 | 0 | switch (key_type) { |
858 | 0 | case CEB_KT_U32: |
859 | 0 | *ret_nside = key_u32 >= k->u32; |
860 | 0 | break; |
861 | 0 | case CEB_KT_U64: |
862 | 0 | *ret_nside = key_u64 >= k->u64; |
863 | 0 | break; |
864 | 0 | case CEB_KT_MB: |
865 | 0 | *ret_nside = (uint64_t)plen / 8 == key_u64 || memcmp(key_ptr + plen / 8, k->mb + plen / 8, key_u64 - plen / 8) >= 0; |
866 | 0 | break; |
867 | 0 | case CEB_KT_IM: |
868 | 0 | *ret_nside = (uint64_t)plen / 8 == key_u64 || memcmp(key_ptr + plen / 8, k->ptr + plen / 8, key_u64 - plen / 8) >= 0; |
869 | 0 | break; |
870 | 0 | case CEB_KT_ST: |
871 | 0 | *ret_nside = found || strcmp(key_ptr + plen / 8, (const void *)k->str + plen / 8) >= 0; |
872 | 0 | break; |
873 | 0 | case CEB_KT_IS: |
874 | 0 | *ret_nside = found || strcmp(key_ptr + plen / 8, (const void *)k->ptr + plen / 8) >= 0; |
875 | 0 | break; |
876 | 0 | case CEB_KT_ADDR: |
877 | 0 | *ret_nside = (uintptr_t)key_ptr >= (uintptr_t)p; |
878 | 0 | break; |
879 | 0 | } |
880 | 0 | } |
881 | | |
882 | 0 | if (ret_root) |
883 | 0 | *ret_root = root; |
884 | | |
885 | | /* info needed by delete */ |
886 | 0 | if (ret_lpside) |
887 | 0 | *ret_lpside = lpside; |
888 | |
|
889 | 0 | if (ret_lparent) |
890 | 0 | *ret_lparent = lparent; |
891 | |
|
892 | 0 | if (ret_npside) |
893 | 0 | *ret_npside = npside; |
894 | |
|
895 | 0 | if (ret_nparent) |
896 | 0 | *ret_nparent = nparent; |
897 | |
|
898 | 0 | if (ret_gpside) |
899 | 0 | *ret_gpside = gpside; |
900 | |
|
901 | 0 | if (ret_gparent) |
902 | 0 | *ret_gparent = gparent; |
903 | |
|
904 | 0 | if (ret_back) |
905 | 0 | *ret_back = bnode; |
906 | |
|
907 | 0 | dbg(__LINE__, "_ret____", meth, kofs, key_type, root, p, key_u32, key_u64, key_ptr, pxor32, pxor64, plen); |
908 | |
|
909 | 0 | if (meth >= CEB_WM_KEQ) { |
910 | | /* For lookups, an equal value means an instant return. For insertions, |
911 | | * it is the same, we want to return the previously existing value so |
912 | | * that the caller can decide what to do. For deletion, we also want to |
913 | | * return the pointer that's about to be deleted. |
914 | | */ |
915 | 0 | if (key_type == CEB_KT_U32) { |
916 | 0 | if ((meth == CEB_WM_KEQ && k->u32 == key_u32) || |
917 | 0 | (meth == CEB_WM_KNX && k->u32 == key_u32) || |
918 | 0 | (meth == CEB_WM_KPR && k->u32 == key_u32) || |
919 | 0 | (meth == CEB_WM_KGE && k->u32 >= key_u32) || |
920 | 0 | (meth == CEB_WM_KGT && k->u32 > key_u32) || |
921 | 0 | (meth == CEB_WM_KLE && k->u32 <= key_u32) || |
922 | 0 | (meth == CEB_WM_KLT && k->u32 < key_u32)) |
923 | 0 | return p; |
924 | 0 | } |
925 | 0 | else if (key_type == CEB_KT_U64) { |
926 | 0 | if ((meth == CEB_WM_KEQ && k->u64 == key_u64) || |
927 | 0 | (meth == CEB_WM_KNX && k->u64 == key_u64) || |
928 | 0 | (meth == CEB_WM_KPR && k->u64 == key_u64) || |
929 | 0 | (meth == CEB_WM_KGE && k->u64 >= key_u64) || |
930 | 0 | (meth == CEB_WM_KGT && k->u64 > key_u64) || |
931 | 0 | (meth == CEB_WM_KLE && k->u64 <= key_u64) || |
932 | 0 | (meth == CEB_WM_KLT && k->u64 < key_u64)) |
933 | 0 | return p; |
934 | 0 | } |
935 | 0 | else if (key_type == CEB_KT_MB) { |
936 | 0 | int diff; |
937 | |
|
938 | 0 | if ((uint64_t)plen / 8 == key_u64) |
939 | 0 | diff = 0; |
940 | 0 | else |
941 | 0 | diff = memcmp(k->mb + plen / 8, key_ptr + plen / 8, key_u64 - plen / 8); |
942 | |
|
943 | 0 | if ((meth == CEB_WM_KEQ && diff == 0) || |
944 | 0 | (meth == CEB_WM_KNX && diff == 0) || |
945 | 0 | (meth == CEB_WM_KPR && diff == 0) || |
946 | 0 | (meth == CEB_WM_KGE && diff >= 0) || |
947 | 0 | (meth == CEB_WM_KGT && diff > 0) || |
948 | 0 | (meth == CEB_WM_KLE && diff <= 0) || |
949 | 0 | (meth == CEB_WM_KLT && diff < 0)) |
950 | 0 | return p; |
951 | 0 | } |
952 | 0 | else if (key_type == CEB_KT_IM) { |
953 | 0 | int diff; |
954 | |
|
955 | 0 | if ((uint64_t)plen / 8 == key_u64) |
956 | 0 | diff = 0; |
957 | 0 | else |
958 | 0 | diff = memcmp(k->ptr + plen / 8, key_ptr + plen / 8, key_u64 - plen / 8); |
959 | |
|
960 | 0 | if ((meth == CEB_WM_KEQ && diff == 0) || |
961 | 0 | (meth == CEB_WM_KNX && diff == 0) || |
962 | 0 | (meth == CEB_WM_KPR && diff == 0) || |
963 | 0 | (meth == CEB_WM_KGE && diff >= 0) || |
964 | 0 | (meth == CEB_WM_KGT && diff > 0) || |
965 | 0 | (meth == CEB_WM_KLE && diff <= 0) || |
966 | 0 | (meth == CEB_WM_KLT && diff < 0)) |
967 | 0 | return p; |
968 | 0 | } |
969 | 0 | else if (key_type == CEB_KT_ST) { |
970 | 0 | int diff; |
971 | |
|
972 | 0 | if (found) |
973 | 0 | diff = 0; |
974 | 0 | else |
975 | 0 | diff = strcmp((const void *)k->str + plen / 8, key_ptr + plen / 8); |
976 | |
|
977 | 0 | if ((meth == CEB_WM_KEQ && diff == 0) || |
978 | 0 | (meth == CEB_WM_KNX && diff == 0) || |
979 | 0 | (meth == CEB_WM_KPR && diff == 0) || |
980 | 0 | (meth == CEB_WM_KGE && diff >= 0) || |
981 | 0 | (meth == CEB_WM_KGT && diff > 0) || |
982 | 0 | (meth == CEB_WM_KLE && diff <= 0) || |
983 | 0 | (meth == CEB_WM_KLT && diff < 0)) |
984 | 0 | return p; |
985 | 0 | } |
986 | 0 | else if (key_type == CEB_KT_IS) { |
987 | 0 | int diff; |
988 | |
|
989 | 0 | if (found) |
990 | 0 | diff = 0; |
991 | 0 | else |
992 | 0 | diff = strcmp((const void *)k->ptr + plen / 8, key_ptr + plen / 8); |
993 | |
|
994 | 0 | if ((meth == CEB_WM_KEQ && diff == 0) || |
995 | 0 | (meth == CEB_WM_KNX && diff == 0) || |
996 | 0 | (meth == CEB_WM_KPR && diff == 0) || |
997 | 0 | (meth == CEB_WM_KGE && diff >= 0) || |
998 | 0 | (meth == CEB_WM_KGT && diff > 0) || |
999 | 0 | (meth == CEB_WM_KLE && diff <= 0) || |
1000 | 0 | (meth == CEB_WM_KLT && diff < 0)) |
1001 | 0 | return p; |
1002 | 0 | } |
1003 | 0 | else if (key_type == CEB_KT_ADDR) { |
1004 | 0 | if ((meth == CEB_WM_KEQ && (uintptr_t)p == (uintptr_t)key_ptr) || |
1005 | 0 | (meth == CEB_WM_KNX && (uintptr_t)p == (uintptr_t)key_ptr) || |
1006 | 0 | (meth == CEB_WM_KPR && (uintptr_t)p == (uintptr_t)key_ptr) || |
1007 | 0 | (meth == CEB_WM_KGE && (uintptr_t)p >= (uintptr_t)key_ptr) || |
1008 | 0 | (meth == CEB_WM_KGT && (uintptr_t)p > (uintptr_t)key_ptr) || |
1009 | 0 | (meth == CEB_WM_KLE && (uintptr_t)p <= (uintptr_t)key_ptr) || |
1010 | 0 | (meth == CEB_WM_KLT && (uintptr_t)p < (uintptr_t)key_ptr)) |
1011 | 0 | return p; |
1012 | 0 | } |
1013 | 0 | } else if (meth == CEB_WM_FST || meth == CEB_WM_LST) { |
1014 | 0 | return p; |
1015 | 0 | } else if (meth == CEB_WM_PRV || meth == CEB_WM_NXT) { |
1016 | 0 | return p; |
1017 | 0 | } |
1018 | | |
1019 | | /* lookups and deletes fail here */ |
1020 | | |
1021 | | /* let's return NULL to indicate the key was not found. For a lookup or |
1022 | | * a delete, it's a failure. For an insert, it's an invitation to the |
1023 | | * caller to proceed since the element is not there. |
1024 | | */ |
1025 | 0 | return NULL; |
1026 | | #if __GNUC_PREREQ__(12, 0) |
1027 | | #pragma GCC diagnostic pop |
1028 | | #endif |
1029 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_descend Unexecuted instantiation: cebus_tree.c:_cebu_descend |
1030 | | |
1031 | | |
1032 | | /* Generic tree insertion function for trees with unique keys. Inserts node |
1033 | | * <node> into tree <tree>, with key type <key_type> and key <key_*>. |
1034 | | * Returns the inserted node or the one that already contains the same key. |
1035 | | */ |
1036 | | static inline __attribute__((always_inline)) |
1037 | | struct ceb_node *_cebu_insert(struct ceb_node **root, |
1038 | | struct ceb_node *node, |
1039 | | ptrdiff_t kofs, |
1040 | | enum ceb_key_type key_type, |
1041 | | uint32_t key_u32, |
1042 | | uint64_t key_u64, |
1043 | | const void *key_ptr) |
1044 | 0 | { |
1045 | 0 | struct ceb_node **parent; |
1046 | 0 | struct ceb_node *ret; |
1047 | 0 | int nside; |
1048 | |
|
1049 | 0 | if (!*root) { |
1050 | | /* empty tree, insert a leaf only */ |
1051 | 0 | node->b[0] = node->b[1] = node; |
1052 | 0 | *root = node; |
1053 | 0 | return node; |
1054 | 0 | } |
1055 | | |
1056 | 0 | ret = _cebu_descend(root, CEB_WM_KEQ, kofs, key_type, key_u32, key_u64, key_ptr, &nside, &parent, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1057 | |
|
1058 | 0 | if (!ret) { |
1059 | | /* The key was not in the tree, we can insert it. Better use an |
1060 | | * "if" like this because the inline function above already has |
1061 | | * quite identifiable code paths. This reduces the code and |
1062 | | * optimizes it a bit. |
1063 | | */ |
1064 | 0 | if (nside) { |
1065 | 0 | node->b[1] = node; |
1066 | 0 | node->b[0] = *parent; |
1067 | 0 | } else { |
1068 | 0 | node->b[0] = node; |
1069 | 0 | node->b[1] = *parent; |
1070 | 0 | } |
1071 | 0 | *parent = node; |
1072 | 0 | ret = node; |
1073 | 0 | } |
1074 | 0 | return ret; |
1075 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_insert Unexecuted instantiation: cebus_tree.c:_cebu_insert |
1076 | | |
1077 | | /* Returns the first node or NULL if not found, assuming a tree made of keys of |
1078 | | * type <key_type>. |
1079 | | */ |
1080 | | static inline __attribute__((always_inline)) |
1081 | | struct ceb_node *_cebu_first(struct ceb_node **root, |
1082 | | ptrdiff_t kofs, |
1083 | | enum ceb_key_type key_type) |
1084 | 0 | { |
1085 | 0 | if (!*root) |
1086 | 0 | return NULL; |
1087 | | |
1088 | 0 | return _cebu_descend(root, CEB_WM_FST, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1089 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_first Unexecuted instantiation: cebus_tree.c:_cebu_first |
1090 | | |
1091 | | /* Returns the last node or NULL if not found, assuming a tree made of keys of |
1092 | | * type <key_type>. |
1093 | | */ |
1094 | | static inline __attribute__((always_inline)) |
1095 | | struct ceb_node *_cebu_last(struct ceb_node **root, |
1096 | | ptrdiff_t kofs, |
1097 | | enum ceb_key_type key_type) |
1098 | 0 | { |
1099 | 0 | if (!*root) |
1100 | 0 | return NULL; |
1101 | | |
1102 | 0 | return _cebu_descend(root, CEB_WM_LST, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1103 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_last Unexecuted instantiation: cebus_tree.c:_cebu_last |
1104 | | |
1105 | | /* Searches in the tree <root> made of keys of type <key_type>, for the next |
1106 | | * node after the one containing the key <key_*>. Returns NULL if not found. |
1107 | | * It's up to the caller to pass the current node's key in <key_*>. The |
1108 | | * approach consists in looking up that node first, recalling the last time a |
1109 | | * left turn was made, and returning the first node along the right branch at |
1110 | | * that fork. |
1111 | | */ |
1112 | | static inline __attribute__((always_inline)) |
1113 | | struct ceb_node *_cebu_next(struct ceb_node **root, |
1114 | | ptrdiff_t kofs, |
1115 | | enum ceb_key_type key_type, |
1116 | | uint32_t key_u32, |
1117 | | uint64_t key_u64, |
1118 | | const void *key_ptr) |
1119 | 0 | { |
1120 | 0 | struct ceb_node *restart; |
1121 | |
|
1122 | 0 | if (!*root) |
1123 | 0 | return NULL; |
1124 | | |
1125 | 0 | if (!_cebu_descend(root, CEB_WM_KNX, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart)) |
1126 | 0 | return NULL; |
1127 | | |
1128 | 0 | if (!restart) |
1129 | 0 | return NULL; |
1130 | | |
1131 | 0 | return _cebu_descend(&restart, CEB_WM_NXT, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1132 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_next Unexecuted instantiation: cebus_tree.c:_cebu_next |
1133 | | |
1134 | | /* Searches in the tree <root> made of keys of type <key_type>, for the prev |
1135 | | * node before the one containing the key <key_*>. Returns NULL if not found. |
1136 | | * It's up to the caller to pass the current node's key in <key_*>. The |
1137 | | * approach consists in looking up that node first, recalling the last time a |
1138 | | * right turn was made, and returning the last node along the left branch at |
1139 | | * that fork. |
1140 | | */ |
1141 | | static inline __attribute__((always_inline)) |
1142 | | struct ceb_node *_cebu_prev(struct ceb_node **root, |
1143 | | ptrdiff_t kofs, |
1144 | | enum ceb_key_type key_type, |
1145 | | uint32_t key_u32, |
1146 | | uint64_t key_u64, |
1147 | | const void *key_ptr) |
1148 | 0 | { |
1149 | 0 | struct ceb_node *restart; |
1150 | |
|
1151 | 0 | if (!*root) |
1152 | 0 | return NULL; |
1153 | | |
1154 | 0 | if (!_cebu_descend(root, CEB_WM_KPR, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart)) |
1155 | 0 | return NULL; |
1156 | | |
1157 | 0 | if (!restart) |
1158 | 0 | return NULL; |
1159 | | |
1160 | 0 | return _cebu_descend(&restart, CEB_WM_PRV, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1161 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_prev Unexecuted instantiation: cebus_tree.c:_cebu_prev |
1162 | | |
1163 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1164 | | * containing the key <key_*>. Returns NULL if not found. |
1165 | | */ |
1166 | | static inline __attribute__((always_inline)) |
1167 | | struct ceb_node *_cebu_lookup(struct ceb_node **root, |
1168 | | ptrdiff_t kofs, |
1169 | | enum ceb_key_type key_type, |
1170 | | uint32_t key_u32, |
1171 | | uint64_t key_u64, |
1172 | | const void *key_ptr) |
1173 | 0 | { |
1174 | 0 | if (!*root) |
1175 | 0 | return NULL; |
1176 | | |
1177 | 0 | return _cebu_descend(root, CEB_WM_KEQ, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1178 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_lookup Unexecuted instantiation: cebus_tree.c:_cebu_lookup |
1179 | | |
1180 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1181 | | * containing the key <key_*> or the highest one that's lower than it. Returns |
1182 | | * NULL if not found. |
1183 | | */ |
1184 | | static inline __attribute__((always_inline)) |
1185 | | struct ceb_node *_cebu_lookup_le(struct ceb_node **root, |
1186 | | ptrdiff_t kofs, |
1187 | | enum ceb_key_type key_type, |
1188 | | uint32_t key_u32, |
1189 | | uint64_t key_u64, |
1190 | | const void *key_ptr) |
1191 | 0 | { |
1192 | 0 | struct ceb_node *ret = NULL; |
1193 | 0 | struct ceb_node *restart; |
1194 | |
|
1195 | 0 | if (!*root) |
1196 | 0 | return NULL; |
1197 | | |
1198 | 0 | ret = _cebu_descend(root, CEB_WM_KLE, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart); |
1199 | 0 | if (ret) |
1200 | 0 | return ret; |
1201 | | |
1202 | 0 | if (!restart) |
1203 | 0 | return NULL; |
1204 | | |
1205 | 0 | return _cebu_descend(&restart, CEB_WM_PRV, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1206 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_lookup_le Unexecuted instantiation: cebus_tree.c:_cebu_lookup_le |
1207 | | |
1208 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1209 | | * containing the greatest key that is strictly lower than <key_*>. Returns |
1210 | | * NULL if not found. It's very similar to next() except that the looked up |
1211 | | * value doesn't need to exist. |
1212 | | */ |
1213 | | static inline __attribute__((always_inline)) |
1214 | | struct ceb_node *_cebu_lookup_lt(struct ceb_node **root, |
1215 | | ptrdiff_t kofs, |
1216 | | enum ceb_key_type key_type, |
1217 | | uint32_t key_u32, |
1218 | | uint64_t key_u64, |
1219 | | const void *key_ptr) |
1220 | 0 | { |
1221 | 0 | struct ceb_node *ret = NULL; |
1222 | 0 | struct ceb_node *restart; |
1223 | |
|
1224 | 0 | if (!*root) |
1225 | 0 | return NULL; |
1226 | | |
1227 | 0 | ret = _cebu_descend(root, CEB_WM_KLT, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart); |
1228 | 0 | if (ret) |
1229 | 0 | return ret; |
1230 | | |
1231 | 0 | if (!restart) |
1232 | 0 | return NULL; |
1233 | | |
1234 | 0 | return _cebu_descend(&restart, CEB_WM_PRV, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1235 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_lookup_lt Unexecuted instantiation: cebus_tree.c:_cebu_lookup_lt |
1236 | | |
1237 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1238 | | * containing the key <key_*> or the smallest one that's greater than it. |
1239 | | * Returns NULL if not found. |
1240 | | */ |
1241 | | static inline __attribute__((always_inline)) |
1242 | | struct ceb_node *_cebu_lookup_ge(struct ceb_node **root, |
1243 | | ptrdiff_t kofs, |
1244 | | enum ceb_key_type key_type, |
1245 | | uint32_t key_u32, |
1246 | | uint64_t key_u64, |
1247 | | const void *key_ptr) |
1248 | 0 | { |
1249 | 0 | struct ceb_node *ret = NULL; |
1250 | 0 | struct ceb_node *restart; |
1251 | |
|
1252 | 0 | if (!*root) |
1253 | 0 | return NULL; |
1254 | | |
1255 | 0 | ret = _cebu_descend(root, CEB_WM_KGE, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart); |
1256 | 0 | if (ret) |
1257 | 0 | return ret; |
1258 | | |
1259 | 0 | if (!restart) |
1260 | 0 | return NULL; |
1261 | | |
1262 | 0 | return _cebu_descend(&restart, CEB_WM_NXT, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1263 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_lookup_ge Unexecuted instantiation: cebus_tree.c:_cebu_lookup_ge |
1264 | | |
1265 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1266 | | * containing the lowest key that is strictly greater than <key_*>. Returns |
1267 | | * NULL if not found. It's very similar to prev() except that the looked up |
1268 | | * value doesn't need to exist. |
1269 | | */ |
1270 | | static inline __attribute__((always_inline)) |
1271 | | struct ceb_node *_cebu_lookup_gt(struct ceb_node **root, |
1272 | | ptrdiff_t kofs, |
1273 | | enum ceb_key_type key_type, |
1274 | | uint32_t key_u32, |
1275 | | uint64_t key_u64, |
1276 | | const void *key_ptr) |
1277 | 0 | { |
1278 | 0 | struct ceb_node *ret = NULL; |
1279 | 0 | struct ceb_node *restart; |
1280 | |
|
1281 | 0 | if (!*root) |
1282 | 0 | return NULL; |
1283 | | |
1284 | 0 | ret = _cebu_descend(root, CEB_WM_KGT, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &restart); |
1285 | 0 | if (ret) |
1286 | 0 | return ret; |
1287 | | |
1288 | 0 | if (!restart) |
1289 | 0 | return NULL; |
1290 | | |
1291 | 0 | return _cebu_descend(&restart, CEB_WM_NXT, kofs, key_type, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
1292 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_lookup_gt Unexecuted instantiation: cebus_tree.c:_cebu_lookup_gt |
1293 | | |
1294 | | /* Searches in the tree <root> made of keys of type <key_type>, for the node |
1295 | | * that contains the key <key_*>, and deletes it. If <node> is non-NULL, a |
1296 | | * check is performed and the node found is deleted only if it matches. The |
1297 | | * found node is returned in any case, otherwise NULL if not found. A deleted |
1298 | | * node is detected since it has b[0]==NULL, which this functions also clears |
1299 | | * after operation. The function is idempotent, so it's safe to attempt to |
1300 | | * delete an already deleted node (NULL is returned in this case since the node |
1301 | | * was not in the tree). |
1302 | | */ |
1303 | | static inline __attribute__((always_inline)) |
1304 | | struct ceb_node *_cebu_delete(struct ceb_node **root, |
1305 | | struct ceb_node *node, |
1306 | | ptrdiff_t kofs, |
1307 | | enum ceb_key_type key_type, |
1308 | | uint32_t key_u32, |
1309 | | uint64_t key_u64, |
1310 | | const void *key_ptr) |
1311 | 0 | { |
1312 | 0 | struct ceb_node *lparent, *nparent, *gparent; |
1313 | 0 | int lpside, npside, gpside; |
1314 | 0 | struct ceb_node *ret = NULL; |
1315 | |
|
1316 | 0 | if (node && !node->b[0]) { |
1317 | | /* NULL on a branch means the node is not in the tree */ |
1318 | 0 | return NULL; |
1319 | 0 | } |
1320 | | |
1321 | 0 | if (!*root) { |
1322 | | /* empty tree, the node cannot be there */ |
1323 | 0 | goto done; |
1324 | 0 | } |
1325 | | |
1326 | 0 | ret = _cebu_descend(root, CEB_WM_KEQ, kofs, key_type, key_u32, key_u64, key_ptr, NULL, NULL, |
1327 | 0 | &lparent, &lpside, &nparent, &npside, &gparent, &gpside, NULL); |
1328 | |
|
1329 | 0 | if (!ret) { |
1330 | | /* key not found */ |
1331 | 0 | goto done; |
1332 | 0 | } |
1333 | | |
1334 | 0 | if (ret == node || !node) { |
1335 | 0 | if (&lparent->b[0] == root) { |
1336 | | /* there was a single entry, this one, so we're just |
1337 | | * deleting the nodeless leaf. |
1338 | | */ |
1339 | 0 | *root = NULL; |
1340 | 0 | goto mark_and_leave; |
1341 | 0 | } |
1342 | | |
1343 | | /* then we necessarily have a gparent */ |
1344 | 0 | gparent->b[gpside] = lparent->b[!lpside]; |
1345 | |
|
1346 | 0 | if (lparent == ret) { |
1347 | | /* we're removing the leaf and node together, nothing |
1348 | | * more to do. |
1349 | | */ |
1350 | 0 | goto mark_and_leave; |
1351 | 0 | } |
1352 | | |
1353 | 0 | if (ret->b[0] == ret->b[1]) { |
1354 | | /* we're removing the node-less item, the parent will |
1355 | | * take this role. |
1356 | | */ |
1357 | 0 | lparent->b[0] = lparent->b[1] = lparent; |
1358 | 0 | goto mark_and_leave; |
1359 | 0 | } |
1360 | | |
1361 | | /* more complicated, the node was split from the leaf, we have |
1362 | | * to find a spare one to switch it. The parent node is not |
1363 | | * needed anymore so we can reuse it. |
1364 | | */ |
1365 | 0 | lparent->b[0] = ret->b[0]; |
1366 | 0 | lparent->b[1] = ret->b[1]; |
1367 | 0 | nparent->b[npside] = lparent; |
1368 | |
|
1369 | 0 | mark_and_leave: |
1370 | | /* now mark the node as deleted */ |
1371 | 0 | ret->b[0] = NULL; |
1372 | 0 | } |
1373 | 0 | done: |
1374 | 0 | return ret; |
1375 | 0 | } Unexecuted instantiation: cebu64_tree.c:_cebu_delete Unexecuted instantiation: cebus_tree.c:_cebu_delete |
1376 | | |
1377 | | /* |
1378 | | * Functions used to dump trees in Dot format. |
1379 | | */ |
1380 | | |
1381 | | /* dump the root and its link to the first node or leaf */ |
1382 | | __attribute__((unused)) |
1383 | | static void cebu_default_dump_root(ptrdiff_t kofs, enum ceb_key_type key_type, struct ceb_node *const *root, const void *ctx) |
1384 | 0 | { |
1385 | 0 | const struct ceb_node *node; |
1386 | |
|
1387 | 0 | printf(" \"%lx_n\" [label=\"root\\n%lx\"]\n", (long)root, (long)root); |
1388 | |
|
1389 | 0 | node = *root; |
1390 | 0 | if (node) { |
1391 | | /* under the root we've either a node or the first leaf */ |
1392 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"B\" arrowsize=0.66];\n", |
1393 | 0 | (long)root, (long)node, |
1394 | 0 | (node->b[0] == node->b[1]) ? 'l' : 'n'); |
1395 | 0 | } |
1396 | 0 | } Unexecuted instantiation: cebu64_tree.c:cebu_default_dump_root Unexecuted instantiation: cebus_tree.c:cebu_default_dump_root |
1397 | | |
1398 | | /* dump a node */ |
1399 | | __attribute__((unused)) |
1400 | | static void cebu_default_dump_node(ptrdiff_t kofs, enum ceb_key_type key_type, const struct ceb_node *node, int level, const void *ctx) |
1401 | 0 | { |
1402 | 0 | unsigned long long int_key = 0; |
1403 | 0 | uint64_t pxor, lxor, rxor; |
1404 | |
|
1405 | 0 | switch (key_type) { |
1406 | 0 | case CEB_KT_ADDR: |
1407 | 0 | int_key = (uintptr_t)node; |
1408 | 0 | break; |
1409 | 0 | case CEB_KT_U32: |
1410 | 0 | int_key = NODEK(node, kofs)->u32; |
1411 | 0 | break; |
1412 | 0 | case CEB_KT_U64: |
1413 | 0 | int_key = NODEK(node, kofs)->u64; |
1414 | 0 | break; |
1415 | 0 | default: |
1416 | 0 | break; |
1417 | 0 | } |
1418 | | |
1419 | | /* xor of the keys of the two lower branches */ |
1420 | 0 | pxor = _xor_branches(kofs, key_type, 0, 0, NULL, |
1421 | 0 | node->b[0], node->b[1]); |
1422 | | |
1423 | | /* xor of the keys of the left branch's lower branches */ |
1424 | 0 | lxor = _xor_branches(kofs, key_type, 0, 0, NULL, |
1425 | 0 | (((struct ceb_node*)node->b[0])->b[0]), |
1426 | 0 | (((struct ceb_node*)node->b[0])->b[1])); |
1427 | | |
1428 | | /* xor of the keys of the right branch's lower branches */ |
1429 | 0 | rxor = _xor_branches(kofs, key_type, 0, 0, NULL, |
1430 | 0 | (((struct ceb_node*)node->b[1])->b[0]), |
1431 | 0 | (((struct ceb_node*)node->b[1])->b[1])); |
1432 | |
|
1433 | 0 | switch (key_type) { |
1434 | 0 | case CEB_KT_ADDR: |
1435 | 0 | case CEB_KT_U32: |
1436 | 0 | case CEB_KT_U64: |
1437 | 0 | printf(" \"%lx_n\" [label=\"%lx\\nlev=%d bit=%d\\nkey=%llu\" fillcolor=\"lightskyblue1\"%s];\n", |
1438 | 0 | (long)node, (long)node, level, flsnz(pxor) - 1, int_key, (ctx == node) ? " color=red" : ""); |
1439 | |
|
1440 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"L\" arrowsize=0.66 %s];\n", |
1441 | 0 | (long)node, (long)node->b[0], |
1442 | 0 | (lxor < pxor && ((struct ceb_node*)node->b[0])->b[0] != ((struct ceb_node*)node->b[0])->b[1]) ? 'n' : 'l', |
1443 | 0 | (node == node->b[0]) ? " dir=both" : ""); |
1444 | |
|
1445 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"R\" arrowsize=0.66 %s];\n", |
1446 | 0 | (long)node, (long)node->b[1], |
1447 | 0 | (rxor < pxor && ((struct ceb_node*)node->b[1])->b[0] != ((struct ceb_node*)node->b[1])->b[1]) ? 'n' : 'l', |
1448 | 0 | (node == node->b[1]) ? " dir=both" : ""); |
1449 | 0 | break; |
1450 | 0 | case CEB_KT_MB: |
1451 | 0 | break; |
1452 | 0 | case CEB_KT_IM: |
1453 | 0 | break; |
1454 | 0 | case CEB_KT_ST: |
1455 | 0 | printf(" \"%lx_n\" [label=\"%lx\\nlev=%d bit=%ld\\nkey=\\\"%s\\\"\" fillcolor=\"lightskyblue1\"%s];\n", |
1456 | 0 | (long)node, (long)node, level, (long)pxor, NODEK(node, kofs)->str, (ctx == node) ? " color=red" : ""); |
1457 | |
|
1458 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"L\" arrowsize=0.66 %s];\n", |
1459 | 0 | (long)node, (long)node->b[0], |
1460 | 0 | (lxor > pxor && ((struct ceb_node*)node->b[0])->b[0] != ((struct ceb_node*)node->b[0])->b[1]) ? 'n' : 'l', |
1461 | 0 | (node == node->b[0]) ? " dir=both" : ""); |
1462 | |
|
1463 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"R\" arrowsize=0.66 %s];\n", |
1464 | 0 | (long)node, (long)node->b[1], |
1465 | 0 | (rxor > pxor && ((struct ceb_node*)node->b[1])->b[0] != ((struct ceb_node*)node->b[1])->b[1]) ? 'n' : 'l', |
1466 | 0 | (node == node->b[1]) ? " dir=both" : ""); |
1467 | 0 | break; |
1468 | 0 | case CEB_KT_IS: |
1469 | 0 | printf(" \"%lx_n\" [label=\"%lx\\nlev=%d bit=%ld\\nkey=\\\"%s\\\"\" fillcolor=\"lightskyblue1\"%s];\n", |
1470 | 0 | (long)node, (long)node, level, (long)pxor, NODEK(node, kofs)->ptr, (ctx == node) ? " color=red" : ""); |
1471 | |
|
1472 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"L\" arrowsize=0.66 %s];\n", |
1473 | 0 | (long)node, (long)node->b[0], |
1474 | 0 | (lxor > pxor && ((struct ceb_node*)node->b[0])->b[0] != ((struct ceb_node*)node->b[0])->b[1]) ? 'n' : 'l', |
1475 | 0 | (node == node->b[0]) ? " dir=both" : ""); |
1476 | |
|
1477 | 0 | printf(" \"%lx_n\" -> \"%lx_%c\" [label=\"R\" arrowsize=0.66 %s];\n", |
1478 | 0 | (long)node, (long)node->b[1], |
1479 | 0 | (rxor > pxor && ((struct ceb_node*)node->b[1])->b[0] != ((struct ceb_node*)node->b[1])->b[1]) ? 'n' : 'l', |
1480 | 0 | (node == node->b[1]) ? " dir=both" : ""); |
1481 | 0 | break; |
1482 | 0 | } |
1483 | 0 | } Unexecuted instantiation: cebu64_tree.c:cebu_default_dump_node Unexecuted instantiation: cebus_tree.c:cebu_default_dump_node |
1484 | | |
1485 | | /* dump a leaf */ |
1486 | | __attribute__((unused)) |
1487 | | static void cebu_default_dump_leaf(ptrdiff_t kofs, enum ceb_key_type key_type, const struct ceb_node *node, int level, const void *ctx) |
1488 | 0 | { |
1489 | 0 | unsigned long long int_key = 0; |
1490 | 0 | uint64_t pxor; |
1491 | |
|
1492 | 0 | switch (key_type) { |
1493 | 0 | case CEB_KT_ADDR: |
1494 | 0 | int_key = (uintptr_t)node; |
1495 | 0 | break; |
1496 | 0 | case CEB_KT_U32: |
1497 | 0 | int_key = NODEK(node, kofs)->u32; |
1498 | 0 | break; |
1499 | 0 | case CEB_KT_U64: |
1500 | 0 | int_key = NODEK(node, kofs)->u64; |
1501 | 0 | break; |
1502 | 0 | default: |
1503 | 0 | break; |
1504 | 0 | } |
1505 | | |
1506 | | /* xor of the keys of the two lower branches */ |
1507 | 0 | pxor = _xor_branches(kofs, key_type, 0, 0, NULL, |
1508 | 0 | node->b[0], node->b[1]); |
1509 | |
|
1510 | 0 | switch (key_type) { |
1511 | 0 | case CEB_KT_ADDR: |
1512 | 0 | case CEB_KT_U32: |
1513 | 0 | case CEB_KT_U64: |
1514 | 0 | if (node->b[0] == node->b[1]) |
1515 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d\\nkey=%llu\\n\" fillcolor=\"green\"%s];\n", |
1516 | 0 | (long)node, (long)node, level, int_key, (ctx == node) ? " color=red" : ""); |
1517 | 0 | else |
1518 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d bit=%d\\nkey=%llu\\n\" fillcolor=\"yellow\"%s];\n", |
1519 | 0 | (long)node, (long)node, level, flsnz(pxor) - 1, int_key, (ctx == node) ? " color=red" : ""); |
1520 | 0 | break; |
1521 | 0 | case CEB_KT_MB: |
1522 | 0 | break; |
1523 | 0 | case CEB_KT_IM: |
1524 | 0 | break; |
1525 | 0 | case CEB_KT_ST: |
1526 | 0 | if (node->b[0] == node->b[1]) |
1527 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d\\nkey=\\\"%s\\\"\\n\" fillcolor=\"green\"%s];\n", |
1528 | 0 | (long)node, (long)node, level, NODEK(node, kofs)->str, (ctx == node) ? " color=red" : ""); |
1529 | 0 | else |
1530 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d bit=%ld\\nkey=\\\"%s\\\"\\n\" fillcolor=\"yellow\"%s];\n", |
1531 | 0 | (long)node, (long)node, level, (long)pxor, NODEK(node, kofs)->str, (ctx == node) ? " color=red" : ""); |
1532 | 0 | break; |
1533 | 0 | case CEB_KT_IS: |
1534 | 0 | if (node->b[0] == node->b[1]) |
1535 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d\\nkey=\\\"%s\\\"\\n\" fillcolor=\"green\"%s];\n", |
1536 | 0 | (long)node, (long)node, level, NODEK(node, kofs)->ptr, (ctx == node) ? " color=red" : ""); |
1537 | 0 | else |
1538 | 0 | printf(" \"%lx_l\" [label=\"%lx\\nlev=%d bit=%ld\\nkey=\\\"%s\\\"\\n\" fillcolor=\"yellow\"%s];\n", |
1539 | 0 | (long)node, (long)node, level, (long)pxor, NODEK(node, kofs)->ptr, (ctx == node) ? " color=red" : ""); |
1540 | 0 | break; |
1541 | 0 | } |
1542 | 0 | } Unexecuted instantiation: cebu64_tree.c:cebu_default_dump_leaf Unexecuted instantiation: cebus_tree.c:cebu_default_dump_leaf |
1543 | | |
1544 | | /* Dumps a tree through the specified callbacks, falling back to the default |
1545 | | * callbacks above if left NULL. |
1546 | | */ |
1547 | | __attribute__((unused)) |
1548 | | static const struct ceb_node *cebu_default_dump_tree(ptrdiff_t kofs, enum ceb_key_type key_type, struct ceb_node *const *root, |
1549 | | uint64_t pxor, const void *last, int level, const void *ctx, |
1550 | | void (*root_dump)(ptrdiff_t kofs, enum ceb_key_type key_type, struct ceb_node *const *root, const void *ctx), |
1551 | | void (*node_dump)(ptrdiff_t kofs, enum ceb_key_type key_type, const struct ceb_node *node, int level, const void *ctx), |
1552 | | void (*leaf_dump)(ptrdiff_t kofs, enum ceb_key_type key_type, const struct ceb_node *node, int level, const void *ctx)) |
1553 | 0 | { |
1554 | 0 | const struct ceb_node *node = *root; |
1555 | 0 | uint64_t xor; |
1556 | |
|
1557 | 0 | if (!node) /* empty tree */ |
1558 | 0 | return node; |
1559 | | |
1560 | 0 | if (!root_dump) |
1561 | 0 | root_dump = cebu_default_dump_root; |
1562 | |
|
1563 | 0 | if (!node_dump) |
1564 | 0 | node_dump = cebu_default_dump_node; |
1565 | |
|
1566 | 0 | if (!leaf_dump) |
1567 | 0 | leaf_dump = cebu_default_dump_leaf; |
1568 | |
|
1569 | 0 | if (!level) { |
1570 | | /* dump the first arrow */ |
1571 | 0 | root_dump(kofs, key_type, root, ctx); |
1572 | 0 | } |
1573 | | |
1574 | | /* regular nodes, all branches are canonical */ |
1575 | |
|
1576 | 0 | if (node->b[0] == node->b[1]) { |
1577 | | /* first inserted leaf */ |
1578 | 0 | leaf_dump(kofs, key_type, node, level, ctx); |
1579 | 0 | return node; |
1580 | 0 | } |
1581 | | |
1582 | 0 | xor = _xor_branches(kofs, key_type, 0, 0, NULL, |
1583 | 0 | node->b[0], node->b[1]); |
1584 | |
|
1585 | 0 | switch (key_type) { |
1586 | 0 | case CEB_KT_ADDR: |
1587 | 0 | case CEB_KT_U32: |
1588 | 0 | case CEB_KT_U64: |
1589 | 0 | if (pxor && xor >= pxor) { |
1590 | | /* that's a leaf for a scalar type */ |
1591 | 0 | leaf_dump(kofs, key_type, node, level, ctx); |
1592 | 0 | return node; |
1593 | 0 | } |
1594 | 0 | break; |
1595 | 0 | default: |
1596 | 0 | if (pxor && xor <= pxor) { |
1597 | | /* that's a leaf for a non-scalar type */ |
1598 | 0 | leaf_dump(kofs, key_type, node, level, ctx); |
1599 | 0 | return node; |
1600 | 0 | } |
1601 | 0 | break; |
1602 | 0 | } |
1603 | | |
1604 | | /* that's a regular node */ |
1605 | 0 | node_dump(kofs, key_type, node, level, ctx); |
1606 | |
|
1607 | 0 | last = cebu_default_dump_tree(kofs, key_type, &node->b[0], xor, last, level + 1, ctx, root_dump, node_dump, leaf_dump); |
1608 | 0 | return cebu_default_dump_tree(kofs, key_type, &node->b[1], xor, last, level + 1, ctx, root_dump, node_dump, leaf_dump); |
1609 | 0 | } Unexecuted instantiation: cebu64_tree.c:cebu_default_dump_tree Unexecuted instantiation: cebus_tree.c:cebu_default_dump_tree |
1610 | | |
1611 | | |
1612 | | #endif /* _CEBTREE_PRV_H */ |