/src/haproxy/src/_ceb_int.c
Line | Count | Source |
1 | | /* |
2 | | * Compact Elastic Binary Trees - exported functions operating on integer keys |
3 | | * |
4 | | * Copyright (C) 2014-2025 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 | | /* NOTE: this file is only meant to be included from other C files. It will |
28 | | * use the following private macros that must be defined by the caller: |
29 | | * - CEB_KEY_TYPE: uint32_t, uint64_t, unsigned long |
30 | | * - CEB_KEY_MEMBER: member of the struct ceb_node holding the key |
31 | | * - CEB_MKEY_PFX: function name prefix for multi-key |
32 | | * - CEB_UKEY_PFX: function name prefix for unique keys |
33 | | * |
34 | | * The dump functions will only be build if CEB_ENABLE_DUMP is defined. |
35 | | */ |
36 | | #include "cebtree-prv.h" |
37 | | |
38 | | /* |
39 | | * Below are the functions that support duplicate keys (_ceb_*) |
40 | | */ |
41 | | |
42 | | /*****************************************************************************\ |
43 | | * The declarations below always cause two functions to be declared, one * |
44 | | * starting with "cebs_*" and one with "cebs_ofs_*" which takes a key offset * |
45 | | * just after the root. The one without kofs just has this argument omitted * |
46 | | * from its declaration and replaced with sizeof(struct ceb_node) in the * |
47 | | * call to the underlying functions. * |
48 | | \*****************************************************************************/ |
49 | | |
50 | | /* Inserts node <node> into tree <tree> based on its key that immediately |
51 | | * follows the node. Returns the inserted node or the one that already contains |
52 | | * the same key. |
53 | | */ |
54 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _insert, struct ceb_root **, root, ptrdiff_t, kofs, struct ceb_node *, node) |
55 | 0 | { |
56 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
57 | 0 | int is_dup; |
58 | |
|
59 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
60 | 0 | return _ceb_insert(root, node, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
61 | 0 | else |
62 | 0 | return _ceb_insert(root, node, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
63 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_insert Unexecuted instantiation: ceb64_tree.c:_ceb64_insert |
64 | | |
65 | | /* return the first node or NULL if not found. */ |
66 | | CEB_FDECL2(struct ceb_node *, CEB_MKEY_PFX, _first, struct ceb_root *const *, root, ptrdiff_t, kofs) |
67 | 0 | { |
68 | 0 | int is_dup; |
69 | |
|
70 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
71 | 0 | return _ceb_first(root, kofs, CEB_KT_U32, 0, &is_dup); |
72 | 0 | else |
73 | 0 | return _ceb_first(root, kofs, CEB_KT_U64, 0, &is_dup); |
74 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_first Unexecuted instantiation: ceb64_tree.c:_ceb64_first |
75 | | |
76 | | /* return the last node or NULL if not found. */ |
77 | | CEB_FDECL2(struct ceb_node *, CEB_MKEY_PFX, _last, struct ceb_root *const *, root, ptrdiff_t, kofs) |
78 | 0 | { |
79 | 0 | int is_dup; |
80 | |
|
81 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
82 | 0 | return _ceb_last(root, kofs, CEB_KT_U32, 0, &is_dup); |
83 | 0 | else |
84 | 0 | return _ceb_last(root, kofs, CEB_KT_U64, 0, &is_dup); |
85 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_last Unexecuted instantiation: ceb64_tree.c:_ceb64_last |
86 | | |
87 | | /* look up the specified key, and returns either the node containing it, or |
88 | | * NULL if not found. |
89 | | */ |
90 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _lookup, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
91 | 0 | { |
92 | 0 | int is_dup; |
93 | |
|
94 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
95 | 0 | return _ceb_lookup(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
96 | 0 | else |
97 | 0 | return _ceb_lookup(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
98 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_lookup Unexecuted instantiation: ceb64_tree.c:_ceb64_lookup |
99 | | |
100 | | /* look up the specified key or the highest below it, and returns either the |
101 | | * node containing it, or NULL if not found. |
102 | | */ |
103 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _lookup_le, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
104 | 0 | { |
105 | 0 | int is_dup; |
106 | |
|
107 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
108 | 0 | return _ceb_lookup_le(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
109 | 0 | else |
110 | 0 | return _ceb_lookup_le(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
111 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_lookup_le Unexecuted instantiation: ceb64_tree.c:_ceb64_lookup_le |
112 | | |
113 | | /* look up highest key below the specified one, and returns either the |
114 | | * node containing it, or NULL if not found. |
115 | | */ |
116 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _lookup_lt, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
117 | 0 | { |
118 | 0 | int is_dup; |
119 | |
|
120 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
121 | 0 | return _ceb_lookup_lt(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
122 | 0 | else |
123 | 0 | return _ceb_lookup_lt(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
124 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_lookup_lt Unexecuted instantiation: ceb64_tree.c:_ceb64_lookup_lt |
125 | | |
126 | | /* look up the specified key or the smallest above it, and returns either the |
127 | | * node containing it, or NULL if not found. |
128 | | */ |
129 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _lookup_ge, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
130 | 0 | { |
131 | 0 | int is_dup; |
132 | |
|
133 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
134 | 0 | return _ceb_lookup_ge(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
135 | 0 | else |
136 | 0 | return _ceb_lookup_ge(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
137 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_lookup_ge Unexecuted instantiation: ceb64_tree.c:_ceb64_lookup_ge |
138 | | |
139 | | /* look up the smallest key above the specified one, and returns either the |
140 | | * node containing it, or NULL if not found. |
141 | | */ |
142 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _lookup_gt, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
143 | 0 | { |
144 | 0 | int is_dup; |
145 | |
|
146 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
147 | 0 | return _ceb_lookup_gt(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
148 | 0 | else |
149 | 0 | return _ceb_lookup_gt(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
150 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_lookup_gt Unexecuted instantiation: ceb64_tree.c:_ceb64_lookup_gt |
151 | | |
152 | | /* search for the next node after the specified one, and return it, or NULL if |
153 | | * not found. The approach consists in looking up that node, recalling the last |
154 | | * time a left turn was made, and returning the first node along the right |
155 | | * branch at that fork. |
156 | | */ |
157 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _next_unique, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
158 | 0 | { |
159 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
160 | 0 | int is_dup; |
161 | |
|
162 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
163 | 0 | return _ceb_next_unique(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
164 | 0 | else |
165 | 0 | return _ceb_next_unique(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
166 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_next_unique Unexecuted instantiation: ceb64_tree.c:_ceb64_next_unique |
167 | | |
168 | | /* search for the prev node before the specified one, and return it, or NULL if |
169 | | * not found. The approach consists in looking up that node, recalling the last |
170 | | * time a right turn was made, and returning the last node along the left |
171 | | * branch at that fork. |
172 | | */ |
173 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _prev_unique, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
174 | 0 | { |
175 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
176 | 0 | int is_dup; |
177 | |
|
178 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
179 | 0 | return _ceb_prev_unique(root, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
180 | 0 | else |
181 | 0 | return _ceb_prev_unique(root, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
182 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_prev_unique Unexecuted instantiation: ceb64_tree.c:_ceb64_prev_unique |
183 | | |
184 | | /* search for the next node after the specified one containing the same value, |
185 | | * and return it, or NULL if not found. |
186 | | */ |
187 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _next_dup, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
188 | 0 | { |
189 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
190 | |
|
191 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
192 | 0 | return _ceb_next_dup(root, kofs, CEB_KT_U32, key, 0, NULL, node); |
193 | 0 | else |
194 | 0 | return _ceb_next_dup(root, kofs, CEB_KT_U64, 0, key, NULL, node); |
195 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_next_dup Unexecuted instantiation: ceb64_tree.c:_ceb64_next_dup |
196 | | |
197 | | /* search for the prev node before the specified one containing the same value, |
198 | | * and return it, or NULL if not found. |
199 | | */ |
200 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _prev_dup, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
201 | 0 | { |
202 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
203 | |
|
204 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
205 | 0 | return _ceb_prev_dup(root, kofs, CEB_KT_U32, key, 0, NULL, node); |
206 | 0 | else |
207 | 0 | return _ceb_prev_dup(root, kofs, CEB_KT_U64, 0, key, NULL, node); |
208 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_prev_dup Unexecuted instantiation: ceb64_tree.c:_ceb64_prev_dup |
209 | | |
210 | | /* search for the next node after the specified one, and return it, or NULL if |
211 | | * not found. The approach consists in looking up that node, recalling the last |
212 | | * time a left turn was made, and returning the first node along the right |
213 | | * branch at that fork. |
214 | | */ |
215 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _next, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
216 | 0 | { |
217 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
218 | 0 | int is_dup; |
219 | |
|
220 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
221 | 0 | return _ceb_next(root, kofs, CEB_KT_U32, key, 0, NULL, node, &is_dup); |
222 | 0 | else |
223 | 0 | return _ceb_next(root, kofs, CEB_KT_U64, 0, key, NULL, node, &is_dup); |
224 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_next Unexecuted instantiation: ceb64_tree.c:_ceb64_next |
225 | | |
226 | | /* search for the prev node before the specified one, and return it, or NULL if |
227 | | * not found. The approach consists in looking up that node, recalling the last |
228 | | * time a right turn was made, and returning the last node along the left |
229 | | * branch at that fork. |
230 | | */ |
231 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _prev, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
232 | 0 | { |
233 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
234 | 0 | int is_dup; |
235 | |
|
236 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
237 | 0 | return _ceb_prev(root, kofs, CEB_KT_U32, key, 0, NULL, node, &is_dup); |
238 | 0 | else |
239 | 0 | return _ceb_prev(root, kofs, CEB_KT_U64, 0, key, NULL, node, &is_dup); |
240 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_prev Unexecuted instantiation: ceb64_tree.c:_ceb64_prev |
241 | | |
242 | | /* look up the specified node with its key and deletes it if found, and in any |
243 | | * case, returns the node. |
244 | | */ |
245 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _delete, struct ceb_root **, root, ptrdiff_t, kofs, struct ceb_node *, node) |
246 | 0 | { |
247 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
248 | 0 | int is_dup; |
249 | |
|
250 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
251 | 0 | return _ceb_delete(root, node, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
252 | 0 | else |
253 | 0 | return _ceb_delete(root, node, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
254 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_delete Unexecuted instantiation: ceb64_tree.c:_ceb64_delete |
255 | | |
256 | | /* look up the specified key, and detaches it and returns it if found, or NULL |
257 | | * if not found. |
258 | | */ |
259 | | CEB_FDECL3(struct ceb_node *, CEB_MKEY_PFX, _pick, struct ceb_root **, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
260 | 0 | { |
261 | 0 | int is_dup; |
262 | |
|
263 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
264 | 0 | return _ceb_delete(root, NULL, kofs, CEB_KT_U32, key, 0, NULL, &is_dup); |
265 | 0 | else |
266 | 0 | return _ceb_delete(root, NULL, kofs, CEB_KT_U64, 0, key, NULL, &is_dup); |
267 | 0 | } Unexecuted instantiation: ceb32_tree.c:_ceb32_pick Unexecuted instantiation: ceb64_tree.c:_ceb64_pick |
268 | | |
269 | | /* |
270 | | * Below are the functions that only support unique keys (_cebu_*) |
271 | | */ |
272 | | |
273 | | /*****************************************************************************\ |
274 | | * The declarations below always cause two functions to be declared, one * |
275 | | * starting with "cebu32_*" and one with "cebu32_ofs_*" which takes a key * |
276 | | * offset just after the root. The one without kofs just has this argument * |
277 | | * omitted from its declaration and replaced with sizeof(struct ceb_node) in * |
278 | | * the call to the underlying functions. * |
279 | | \*****************************************************************************/ |
280 | | |
281 | | /* Inserts node <node> into unique tree <tree> based on its key that |
282 | | * immediately follows the node. Returns the inserted node or the one |
283 | | * that already contains the same key. |
284 | | */ |
285 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _insert, struct ceb_root **, root, ptrdiff_t, kofs, struct ceb_node *, node) |
286 | 0 | { |
287 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
288 | |
|
289 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
290 | 0 | return _ceb_insert(root, node, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
291 | 0 | else |
292 | 0 | return _ceb_insert(root, node, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
293 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_insert Unexecuted instantiation: ceb64_tree.c:_cebu64_insert |
294 | | |
295 | | /* return the first node or NULL if not found. */ |
296 | | CEB_FDECL2(struct ceb_node *, CEB_UKEY_PFX, _first, struct ceb_root *const *, root, ptrdiff_t, kofs) |
297 | 0 | { |
298 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
299 | 0 | return _ceb_first(root, kofs, CEB_KT_U32, 0, NULL); |
300 | 0 | else |
301 | 0 | return _ceb_first(root, kofs, CEB_KT_U64, 0, NULL); |
302 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_first Unexecuted instantiation: ceb64_tree.c:_cebu64_first |
303 | | |
304 | | /* return the last node or NULL if not found. */ |
305 | | CEB_FDECL2(struct ceb_node *, CEB_UKEY_PFX, _last, struct ceb_root *const *, root, ptrdiff_t, kofs) |
306 | 0 | { |
307 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
308 | 0 | return _ceb_last(root, kofs, CEB_KT_U32, 0, NULL); |
309 | 0 | else |
310 | 0 | return _ceb_last(root, kofs, CEB_KT_U64, 0, NULL); |
311 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_last Unexecuted instantiation: ceb64_tree.c:_cebu64_last |
312 | | |
313 | | /* look up the specified key, and returns either the node containing it, or |
314 | | * NULL if not found. |
315 | | */ |
316 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _lookup, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
317 | 0 | { |
318 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
319 | 0 | return _ceb_lookup(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
320 | 0 | else |
321 | 0 | return _ceb_lookup(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
322 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_lookup Unexecuted instantiation: ceb64_tree.c:_cebu64_lookup |
323 | | |
324 | | /* look up the specified key or the highest below it, and returns either the |
325 | | * node containing it, or NULL if not found. |
326 | | */ |
327 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _lookup_le, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
328 | 0 | { |
329 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
330 | 0 | return _ceb_lookup_le(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
331 | 0 | else |
332 | 0 | return _ceb_lookup_le(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
333 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_lookup_le Unexecuted instantiation: ceb64_tree.c:_cebu64_lookup_le |
334 | | |
335 | | /* look up highest key below the specified one, and returns either the |
336 | | * node containing it, or NULL if not found. |
337 | | */ |
338 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _lookup_lt, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
339 | 0 | { |
340 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
341 | 0 | return _ceb_lookup_lt(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
342 | 0 | else |
343 | 0 | return _ceb_lookup_lt(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
344 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_lookup_lt Unexecuted instantiation: ceb64_tree.c:_cebu64_lookup_lt |
345 | | |
346 | | /* look up the specified key or the smallest above it, and returns either the |
347 | | * node containing it, or NULL if not found. |
348 | | */ |
349 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _lookup_ge, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
350 | 0 | { |
351 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
352 | 0 | return _ceb_lookup_ge(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
353 | 0 | else |
354 | 0 | return _ceb_lookup_ge(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
355 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_lookup_ge Unexecuted instantiation: ceb64_tree.c:_cebu64_lookup_ge |
356 | | |
357 | | /* look up the smallest key above the specified one, and returns either the |
358 | | * node containing it, or NULL if not found. |
359 | | */ |
360 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _lookup_gt, struct ceb_root *const *, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
361 | 0 | { |
362 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
363 | 0 | return _ceb_lookup_gt(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
364 | 0 | else |
365 | 0 | return _ceb_lookup_gt(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
366 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_lookup_gt Unexecuted instantiation: ceb64_tree.c:_cebu64_lookup_gt |
367 | | |
368 | | /* search for the next node after the specified one, and return it, or NULL if |
369 | | * not found. The approach consists in looking up that node, recalling the last |
370 | | * time a left turn was made, and returning the first node along the right |
371 | | * branch at that fork. |
372 | | */ |
373 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _next, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
374 | 0 | { |
375 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
376 | |
|
377 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
378 | 0 | return _ceb_next_unique(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
379 | 0 | else |
380 | 0 | return _ceb_next_unique(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
381 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_next Unexecuted instantiation: ceb64_tree.c:_cebu64_next |
382 | | |
383 | | /* search for the prev node before the specified one, and return it, or NULL if |
384 | | * not found. The approach consists in looking up that node, recalling the last |
385 | | * time a right turn was made, and returning the last node along the left |
386 | | * branch at that fork. |
387 | | */ |
388 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _prev, struct ceb_root *const *, root, ptrdiff_t, kofs, struct ceb_node *, node) |
389 | 0 | { |
390 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
391 | |
|
392 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
393 | 0 | return _ceb_prev_unique(root, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
394 | 0 | else |
395 | 0 | return _ceb_prev_unique(root, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
396 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_prev Unexecuted instantiation: ceb64_tree.c:_cebu64_prev |
397 | | |
398 | | /* look up the specified node with its key and deletes it if found, and in any |
399 | | * case, returns the node. |
400 | | */ |
401 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _delete, struct ceb_root **, root, ptrdiff_t, kofs, struct ceb_node *, node) |
402 | 0 | { |
403 | 0 | CEB_KEY_TYPE key = NODEK(node, kofs)->CEB_KEY_MEMBER; |
404 | |
|
405 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
406 | 0 | return _ceb_delete(root, node, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
407 | 0 | else |
408 | 0 | return _ceb_delete(root, node, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
409 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_delete Unexecuted instantiation: ceb64_tree.c:_cebu64_delete |
410 | | |
411 | | /* look up the specified key, and detaches it and returns it if found, or NULL |
412 | | * if not found. |
413 | | */ |
414 | | CEB_FDECL3(struct ceb_node *, CEB_UKEY_PFX, _pick, struct ceb_root **, root, ptrdiff_t, kofs, CEB_KEY_TYPE, key) |
415 | 0 | { |
416 | 0 | if (sizeof(CEB_KEY_TYPE) <= 4) |
417 | 0 | return _ceb_delete(root, NULL, kofs, CEB_KT_U32, key, 0, NULL, NULL); |
418 | 0 | else |
419 | 0 | return _ceb_delete(root, NULL, kofs, CEB_KT_U64, 0, key, NULL, NULL); |
420 | 0 | } Unexecuted instantiation: ceb32_tree.c:_cebu32_pick Unexecuted instantiation: ceb64_tree.c:_cebu64_pick |
421 | | |
422 | | /* |
423 | | * Functions used to dump trees in Dot format. These are only enabled if |
424 | | * CEB_ENABLE_DUMP is defined. |
425 | | */ |
426 | | |
427 | | #if defined(CEB_ENABLE_DUMP) |
428 | | |
429 | | #include <stdio.h> |
430 | | #define TO_STR(x) _TO_STR(x) |
431 | | #define _TO_STR(x) #x |
432 | | |
433 | | /* dumps a ceb_node tree using the default functions above. If a node matches |
434 | | * <ctx>, this one will be highlighted in red. If the <sub> value is non-null, |
435 | | * only a subgraph will be printed. If it's null, and root is non-null, then |
436 | | * the tree is dumped at once, otherwise if root is NULL, then a prologue is |
437 | | * dumped when label is not NULL, or the epilogue when label is NULL. As a |
438 | | * summary: |
439 | | * sub root label |
440 | | * 0 NULL NULL epilogue only (closing brace and LF) |
441 | | * 0 NULL text prologue with <text> as label |
442 | | * 0 tree * prologue+tree+epilogue at once |
443 | | * N>0 tree * only the tree, after a prologue and before an epilogue |
444 | | */ |
445 | | CEB_FDECL5(void, CEB_MKEY_PFX, _default_dump, struct ceb_root *const *, root, ptrdiff_t, kofs, const char *, label, const void *, ctx, int, sub) |
446 | | { |
447 | | if (!sub && label) { |
448 | | printf("\ndigraph " TO_STR(CEB_MKEY_PFX) "_tree {\n" |
449 | | " fontname=\"fixed\";\n" |
450 | | " fontsize=8\n" |
451 | | " label=\"%s\"\n" |
452 | | "", label); |
453 | | |
454 | | printf(" node [fontname=\"fixed\" fontsize=8 shape=\"box\" style=\"filled\" color=\"black\" fillcolor=\"white\"];\n" |
455 | | " edge [fontname=\"fixed\" fontsize=8 style=\"solid\" color=\"magenta\" dir=\"forward\"];\n"); |
456 | | } else |
457 | | printf("\n### sub %d ###\n\n", sub); |
458 | | |
459 | | if (root) |
460 | | ceb_imm_default_dump_tree(kofs, sizeof(CEB_KEY_TYPE) <= 4 ? CEB_KT_U32 : CEB_KT_U64, root, 0, NULL, 0, ctx, sub, NULL, NULL, NULL, NULL); |
461 | | |
462 | | if (!sub && (root || !label)) |
463 | | printf("}\n"); |
464 | | } |
465 | | |
466 | | #endif /* CEB_ENABLE_DUMP */ |