Coverage Report

Created: 2025-08-28 06:25

/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 */