File Coverage

pollfd_rbhash.c
Criterion Covered Total %
statement 15 499 3.0
branch 5 336 1.4
condition n/a
subroutine n/a
pod n/a
total 20 835 2.4


line stmt bran cond sub pod time code
1              
2             /*
3             Generated by rbhash.cpppp using command
4              
5             cpppp -p 'max_bits=16' \
6             -p 'namespace=pollfd_rbhash' \
7             -p '@default_search_args=('\''int search_fd'\'')' \
8             -p 'default_search_cmp=search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd' \
9             rbhash.cpppp \
10             -o 'public=pollfd_rbhash.h' \
11             -o pollfd_rbhash.c
12              
13             */
14              
15             #include "pollfd_rbhash.h"
16              
17             // A setting that disables all the runtime sanity checks and safeguards
18             #ifndef POLLFD_RBHASH_RUN_WITH_SCISSORS
19             #define POLLFD_RBHASH_RUN_WITH_SCISSORS 0
20             #endif
21              
22             #ifndef POLLFD_RBHASH_ASSERT
23             /* The assertions of this library are fairly important since so much of the
24             * implementation is exposed to the rest of the program, so only actually
25             * remove the checks if RUN_WITH_SCISSORS is set.
26             */
27             #if POLLFD_RBHASH_RUN_WITH_SCISSORS
28             #define POLLFD_RBHASH_ASSERT(x) (void)0
29             #elif defined(NDEBUG)
30             #define POLLFD_RBHASH_ASSERT(x) if (!(x)) return 0
31             #else
32             #define POLLFD_RBHASH_ASSERT(x) assert(x)
33             #endif
34             #endif
35             void pollfd_rbhash_path_8_init(struct pollfd_rbhash_path_8 *p);
36             void pollfd_rbhash_path_16_init(struct pollfd_rbhash_path_16 *p);
37              
38             /* Only called when capacity is out of bounds. Used by the inline bit-selectors. */
39 0           extern size_t pollfd_rbhash_capacity_bounds_assertion(size_t capacity) {
40 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
41 0           return 0;
42             }
43              
44              
45             /* Find a node in the hash table, or tree. Returns the node_id, or 0 if no
46             * nodes match.
47             *
48             * This is a simplified version of find_path that doesn't keep track of the
49             * path through the tree, saving time but not facilitating inserts or deletes.
50             */
51 57           size_t pollfd_rbhash_find(
52             void *rbhash, size_t capacity, size_t bucket_idx,
53             int search_fd
54             ) {
55 57           size_t node_id= 0;
56             int cmp;
57 57 50         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
58 57           node_id= ((uint8_t *)rbhash)[ POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx ] >> 1;
59 57 50         while (node_id && (cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd))
    50          
60 0           node_id= ((uint8_t *)rbhash)[ (node_id<<1) | (cmp < 0? 0 : 1) ] >> 1;
61             }
62 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
63 0           node_id= ((uint16_t *)rbhash)[ POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx ] >> 1;
64 0 0         while (node_id && (cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd))
    0          
65 0           node_id= ((uint16_t *)rbhash)[ (node_id<<1) | (cmp < 0? 0 : 1) ] >> 1;
66             }
67             else {
68 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
69             }
70 57           return node_id;
71             }
72              
73             /* Find a node in the hash table, and record the path to arrive at the node
74             * or the node pointer where it would exist. The path can be used for
75             * inserting or deleting without re-comparing any elements.
76             *
77             * The path should already have been initialized using `pollfd_rbhash_path_init`.
78             */
79 0           size_t pollfd_rbhash_find_path(
80             void *rbhash, size_t capacity, pollfd_rbhash_path *path, size_t bucket_idx,
81             int search_fd
82             ) {
83 0           size_t ref, node_id= 0;
84 0           int cmp, p_i= 0, p_lim= path->lim;
85 0           path->len= 0; // in case POLLFD_RBHASH_ASSERT calls 'return 0'
86 0 0         POLLFD_RBHASH_ASSERT(p_lim > 0);
87 0 0         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
88 0           uint8_t *rbhash_w= (uint8_t*) rbhash;
89 0           path->refs[0]= POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx;
90 0           node_id= rbhash_w[ path->refs[0] ] >> 1;
91 0 0         while (node_id && (cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd)) {
    0          
92 0           ref= (node_id<<1) | (cmp < 0? 0 : 1);
93 0           ++p_i;
94 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
95 0           path->refs[p_i]= ref;
96 0           node_id= rbhash_w[ref] >> 1;
97             }
98             }
99 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
100 0           uint16_t *rbhash_w= (uint16_t*) rbhash;
101 0           path->refs[0]= POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx;
102 0           node_id= rbhash_w[ path->refs[0] ] >> 1;
103 0 0         while (node_id && (cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd)) {
    0          
104 0           ref= (node_id<<1) | (cmp < 0? 0 : 1);
105 0           ++p_i;
106 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
107 0           path->refs[p_i]= ref;
108 0           node_id= rbhash_w[ref] >> 1;
109             }
110             }
111             else {
112 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
113             }
114 0           path->len= p_i+1;
115 0           return node_id;
116             }
117              
118             /* Insert a node into the hashtable, storing collisions in a tree.
119             * If it finds a node with same key, it returns that index and does not insert
120             * the new node, else it will insert and return your 'new_node' value.
121             * If it returns node 0, you have a corrupted data structure.
122             */
123 122           extern size_t pollfd_rbhash_insert(
124             void *rbhash, size_t capacity, size_t at_node_id, size_t bucket_idx,
125             int search_fd
126             ) {
127 122           size_t node_id= 0, ref= POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx;
128 122           int cmp, p_i= 0, p_lim;
129 122 50         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
130 122           uint8_t *rbhash_w= (uint8_t*) rbhash;
131 122           node_id= rbhash_w[ref] >> 1;
132 122 50         if (!node_id) {
133 122           rbhash_w[ref]= at_node_id << 1;
134 122           return at_node_id;
135             }
136             else {
137             struct pollfd_rbhash_path_8 path;
138 0           pollfd_rbhash_path_8_init(&path);
139 0           p_lim= path.lim;
140 0           path.refs[0]= ref;
141             do {
142 0 0         if (!(cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd))
143 0           return node_id;
144 0           ref= (node_id<<1) | (cmp < 0? 0 : 1);
145 0           ++p_i;
146 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
147 0           path.refs[p_i]= ref;
148 0           node_id= rbhash_w[ref] >> 1;
149 0 0         } while (node_id);
150 0           node_id= at_node_id;
151             // Handle simple case of adding to black parent without invoking balance.
152 0 0         if (!(rbhash_w[path.refs[p_i-1]] & 1)) {
153 0           rbhash_w[ref]= (node_id << 1) | 1;
154 0           return node_id;
155             }
156 0           path.len= p_i+1;
157 0           return pollfd_rbhash_path_insert_8(rbhash_w, (pollfd_rbhash_path*) &path, node_id);
158             }
159             }
160 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
161 0           uint16_t *rbhash_w= (uint16_t*) rbhash;
162 0           node_id= rbhash_w[ref] >> 1;
163 0 0         if (!node_id) {
164 0           rbhash_w[ref]= at_node_id << 1;
165 0           return at_node_id;
166             }
167             else {
168             struct pollfd_rbhash_path_16 path;
169 0           pollfd_rbhash_path_16_init(&path);
170 0           p_lim= path.lim;
171 0           path.refs[0]= ref;
172             do {
173 0 0         if (!(cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd))
174 0           return node_id;
175 0           ref= (node_id<<1) | (cmp < 0? 0 : 1);
176 0           ++p_i;
177 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
178 0           path.refs[p_i]= ref;
179 0           node_id= rbhash_w[ref] >> 1;
180 0 0         } while (node_id);
181 0           node_id= at_node_id;
182             // Handle simple case of adding to black parent without invoking balance.
183 0 0         if (!(rbhash_w[path.refs[p_i-1]] & 1)) {
184 0           rbhash_w[ref]= (node_id << 1) | 1;
185 0           return node_id;
186             }
187 0           path.len= p_i+1;
188 0           return pollfd_rbhash_path_insert_16(rbhash_w, (pollfd_rbhash_path*) &path, node_id);
189             }
190             }
191 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
192 0           return 0;
193             }
194              
195             /* Find and delete a node in the hashtable. If found, this returns the node_id
196             * that was removed. If not found (or if the data structure is currupt) this
197             * returns 0. It may also return 0 if an assertion fails and you have disabled
198             * aborting on assertions.
199             */
200 0           extern size_t pollfd_rbhash_delete(
201             void *rbhash, size_t capacity, size_t bucket_idx,
202             int search_fd
203             ) {
204 0           size_t cur= 0, ref= POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + bucket_idx;
205 0           int cmp, p_i= 0, p_lim;
206 0 0         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
207 0           uint8_t *rbhash_w= (uint8_t*) rbhash;
208 0 0         if ((cur= rbhash_w[ref])) {
209             struct pollfd_rbhash_path_8 path;
210 0           pollfd_rbhash_path_8_init(&path);
211 0           p_lim= path.lim;
212 0           path.refs[0]= ref;
213            
214             #define node_id (cur >> 1)
215 0 0         while ((cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd)) {
216             #undef node_id
217 0           ref= (cur|1) ^ (cmp < 0? 1 : 0);
218 0           cur= rbhash_w[ref];
219 0 0         if (!cur)
220 0           return 0;
221 0           ++p_i;
222 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
223 0           path.refs[p_i]= ref;
224             }
225 0           path.len= p_i+1;
226 0           return pollfd_rbhash_path_delete_8(rbhash_w, (pollfd_rbhash_path*) &path);
227             }
228             }
229 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
230 0           uint16_t *rbhash_w= (uint16_t*) rbhash;
231 0 0         if ((cur= rbhash_w[ref])) {
232             struct pollfd_rbhash_path_16 path;
233 0           pollfd_rbhash_path_16_init(&path);
234 0           p_lim= path.lim;
235 0           path.refs[0]= ref;
236            
237             #define node_id (cur >> 1)
238 0 0         while ((cmp= search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd)) {
239             #undef node_id
240 0           ref= (cur|1) ^ (cmp < 0? 1 : 0);
241 0           cur= rbhash_w[ref];
242 0 0         if (!cur)
243 0           return 0;
244 0           ++p_i;
245 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
246 0           path.refs[p_i]= ref;
247             }
248 0           path.len= p_i+1;
249 0           return pollfd_rbhash_path_delete_16(rbhash_w, (pollfd_rbhash_path*) &path);
250             }
251             }
252 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
253 0           return 0;
254             }
255              
256              
257             /* Given a path to a node, make that path point to a new node assuming that
258             * the new node contains the same search key that the old node used to.
259             * This is used when moving array elements to a new index where the NodeID
260             * would be different.
261             *
262             * This is a O(1) operation, though building the path probably took O(log N).
263             *
264             * Returns the NodeID that the path previously ended with, and the path has
265             * been modified to end with new_node_id and is still valid. May return
266             * 0 if an assertion fails and you have disabled assertions.
267             */
268 0           extern size_t pollfd_rbhash_path_swap(
269             void *rbhash, size_t capacity, pollfd_rbhash_path *path, size_t new_node_id
270             ) {
271             size_t ref;
272             /* path must point to a node, and new_node_id must not be the sentinel */
273 0 0         POLLFD_RBHASH_ASSERT(path->len > 0 && new_node_id);
    0          
274 0 0         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
275 0           uint8_t *rbhash_w= (uint8_t*) rbhash, prev;
276             // It is an error if new_node_id is not already zeroed
277 0 0         POLLFD_RBHASH_ASSERT(((uint16_t*) rbhash)[new_node_id] == 0);
278             // Swap the references
279 0           ref= path->refs[path->len-1];
280 0           prev= rbhash_w[ref];
281 0           rbhash_w[ref]= (new_node_id << 1) | (prev&1);
282 0           ((uint16_t*) rbhash)[new_node_id]= ((uint16_t*) rbhash)[prev>>1];
283             // and clear out the 'prev' before returning it
284 0           ((uint16_t*) rbhash)[prev>>1]= 0;
285 0           return prev >> 1;
286             }
287 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
288 0           uint16_t *rbhash_w= (uint16_t*) rbhash, prev;
289             // It is an error if new_node_id is not already zeroed
290 0 0         POLLFD_RBHASH_ASSERT(((uint32_t*) rbhash)[new_node_id] == 0);
291             // Swap the references
292 0           ref= path->refs[path->len-1];
293 0           prev= rbhash_w[ref];
294 0           rbhash_w[ref]= (new_node_id << 1) | (prev&1);
295 0           ((uint32_t*) rbhash)[new_node_id]= ((uint32_t*) rbhash)[prev>>1];
296             // and clear out the 'prev' before returning it
297 0           ((uint32_t*) rbhash)[prev>>1]= 0;
298 0           return prev >> 1;
299             }
300 0 0         POLLFD_RBHASH_ASSERT(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16);
301 0           return 0;
302             }
303              
304             /* Insert a node_id at the end of a path which points to the Sentinel.
305             * The final ref will be updated to point to node_id, and then the tree
306             * will be balanced according to the Red/Black algorithm. The path is
307             * destroyed in the process and should not be used after this call.
308             * (the path could be updated during balance rotations, but would add
309             * overhead and users are unlikely to need it afterward anyway)
310             *
311             * Returns the node_id on success, or 0 on an assertion failure if you
312             * disabled assertions.
313             */
314 0           extern size_t pollfd_rbhash_path_insert_8(
315             uint8_t *rbhash, pollfd_rbhash_path *path, size_t node_id
316             ) {
317             /*
318             Legend for deciphering crazy bitwise operations below:
319             X_ref - the index within the rbhash array which holds X
320             X= rbhash[X_ref] - an integer of ((node_id << 1) | red)
321             i.e. if pos is like a pointer with embedded color information,
322             pos_ref is like a pointer to that pointer.
323             X & 1 - 1 = red, 0 = black
324             X >> 1 - the node_id X is pointing to
325             If X_ref is from a tree node (true for all path->refs[i > 0]) then
326             the location of the ref also indicates which node it belongs to,
327             by virtue of nodes being located at rbhash[node_id*2].
328             X_ref >> 1 - the node_id of the parent of X
329             X_ref & 1 - true if X is the right-subtree of its parent
330             X_ref ^ 1 - a ref to the sibling of X
331             X | 1 - the ref to X's node_id's right subtree
332             X >> 1 << 1 - the ref to X's node_id's left subtree
333             (X|1) ^ 1 - same, maybe optimized if (X|1) is already in a register
334             X ^ 1 - a shortcut for one of the above when the color is known
335             */
336 0           int p_i= path->len - 1;
337             // Empty paths or paths ending with a non-Sentinel reference are invalid.
338 0 0         POLLFD_RBHASH_ASSERT(path->len > 0 && rbhash[path->refs[p_i]] == 0);
    0          
339             // Add new_node to the final parent-ref of the path.
340             // If p_i is 0, this will be altering the hash bucket.
341 0           rbhash[path->refs[p_i--]]= (node_id << 1) | 1; // and make it red
342             // 'pos' will be the parent node of that.
343 0 0         while (p_i > 0) {
344 0           uint8_t pos_ref= path->refs[p_i--];
345 0           uint8_t pos= rbhash[pos_ref];
346 0           uint8_t parent_ref= path->refs[p_i];
347             // if current is a black node, no rotations needed
348 0 0         if (!(pos & 1))
349 0           break;
350             // pos is red, its new child is red, and parent will be black.
351             // if the sibling is also red, we can pull down the color black from the parent
352             // if not, need a rotation.
353 0 0         if (!(rbhash[pos_ref^1]&1)) {
354             // Sibling is black, need a rotation
355             // if the imbalanced child (red node) is on the same side as the parent,
356             // need to rotate those lower nodes to the opposite side in preparation
357             // for the rotation.
358             // e.g. if pos_ref is leftward (even) and pos's rightward child (odd) is the red one...
359 0           uint8_t child_ref= pos ^ (pos_ref&1);
360 0           uint8_t child= rbhash[child_ref];
361 0 0         if (child&1) {
362             // rotate pos toward [side] so parent's [side] now points to pos's [otherside]
363             // set pos's child-ref to child's [otherside] ref
364 0           uint8_t near_grandchild_ref= child ^ (child_ref&1);
365 0           rbhash[child_ref]= rbhash[near_grandchild_ref];
366             // set child's [side] to pos
367 0           rbhash[near_grandchild_ref]= pos;
368 0           pos= child; // keep pos as a red node, soon to become black
369 0           rbhash[pos_ref]= child;
370             // parent's [side] has not been updated here, but is about to become 'child'
371 0           child_ref= near_grandchild_ref^1;
372 0           child= rbhash[child_ref];
373             }
374             // Now we can rotate toward parent to balance the tree.
375 0           rbhash[pos_ref]= child;
376 0           rbhash[child_ref]= pos_ref|1; // = parent, colored red. simplification of ((pos_ref>>1)<<1)|1
377 0           rbhash[parent_ref]= pos^1; // also make pos black
378             // rotation finished, exit.
379 0           break;
380             }
381 0           rbhash[pos_ref^1] ^= 1; // toggle color of sibling
382 0           rbhash[pos_ref]= pos^1; // toggle color of pos
383 0           rbhash[parent_ref] ^= 1; // toggle color of parent
384             // Now pos is black.
385             // Jump twice up the tree so that once again, pos has one red child.
386 0           p_i--;
387             }
388             // Root of tree is always black
389 0 0         if (rbhash[path->refs[0]] & 1)
390 0           rbhash[path->refs[0]] ^= 1;
391             #if !POLLFD_RBHASH_RUN_WITH_SCISSORS
392             // Path is no longer valid, because rotations may have destroyed it.
393 0           path->len= 0;
394             #endif
395 0           return node_id;
396             }
397 0           extern size_t pollfd_rbhash_path_insert_16(
398             uint16_t *rbhash, pollfd_rbhash_path *path, size_t node_id
399             ) {
400             /*
401             Legend for deciphering crazy bitwise operations below:
402             X_ref - the index within the rbhash array which holds X
403             X= rbhash[X_ref] - an integer of ((node_id << 1) | red)
404             i.e. if pos is like a pointer with embedded color information,
405             pos_ref is like a pointer to that pointer.
406             X & 1 - 1 = red, 0 = black
407             X >> 1 - the node_id X is pointing to
408             If X_ref is from a tree node (true for all path->refs[i > 0]) then
409             the location of the ref also indicates which node it belongs to,
410             by virtue of nodes being located at rbhash[node_id*2].
411             X_ref >> 1 - the node_id of the parent of X
412             X_ref & 1 - true if X is the right-subtree of its parent
413             X_ref ^ 1 - a ref to the sibling of X
414             X | 1 - the ref to X's node_id's right subtree
415             X >> 1 << 1 - the ref to X's node_id's left subtree
416             (X|1) ^ 1 - same, maybe optimized if (X|1) is already in a register
417             X ^ 1 - a shortcut for one of the above when the color is known
418             */
419 0           int p_i= path->len - 1;
420             // Empty paths or paths ending with a non-Sentinel reference are invalid.
421 0 0         POLLFD_RBHASH_ASSERT(path->len > 0 && rbhash[path->refs[p_i]] == 0);
    0          
422             // Add new_node to the final parent-ref of the path.
423             // If p_i is 0, this will be altering the hash bucket.
424 0           rbhash[path->refs[p_i--]]= (node_id << 1) | 1; // and make it red
425             // 'pos' will be the parent node of that.
426 0 0         while (p_i > 0) {
427 0           uint16_t pos_ref= path->refs[p_i--];
428 0           uint16_t pos= rbhash[pos_ref];
429 0           uint16_t parent_ref= path->refs[p_i];
430             // if current is a black node, no rotations needed
431 0 0         if (!(pos & 1))
432 0           break;
433             // pos is red, its new child is red, and parent will be black.
434             // if the sibling is also red, we can pull down the color black from the parent
435             // if not, need a rotation.
436 0 0         if (!(rbhash[pos_ref^1]&1)) {
437             // Sibling is black, need a rotation
438             // if the imbalanced child (red node) is on the same side as the parent,
439             // need to rotate those lower nodes to the opposite side in preparation
440             // for the rotation.
441             // e.g. if pos_ref is leftward (even) and pos's rightward child (odd) is the red one...
442 0           uint16_t child_ref= pos ^ (pos_ref&1);
443 0           uint16_t child= rbhash[child_ref];
444 0 0         if (child&1) {
445             // rotate pos toward [side] so parent's [side] now points to pos's [otherside]
446             // set pos's child-ref to child's [otherside] ref
447 0           uint16_t near_grandchild_ref= child ^ (child_ref&1);
448 0           rbhash[child_ref]= rbhash[near_grandchild_ref];
449             // set child's [side] to pos
450 0           rbhash[near_grandchild_ref]= pos;
451 0           pos= child; // keep pos as a red node, soon to become black
452 0           rbhash[pos_ref]= child;
453             // parent's [side] has not been updated here, but is about to become 'child'
454 0           child_ref= near_grandchild_ref^1;
455 0           child= rbhash[child_ref];
456             }
457             // Now we can rotate toward parent to balance the tree.
458 0           rbhash[pos_ref]= child;
459 0           rbhash[child_ref]= pos_ref|1; // = parent, colored red. simplification of ((pos_ref>>1)<<1)|1
460 0           rbhash[parent_ref]= pos^1; // also make pos black
461             // rotation finished, exit.
462 0           break;
463             }
464 0           rbhash[pos_ref^1] ^= 1; // toggle color of sibling
465 0           rbhash[pos_ref]= pos^1; // toggle color of pos
466 0           rbhash[parent_ref] ^= 1; // toggle color of parent
467             // Now pos is black.
468             // Jump twice up the tree so that once again, pos has one red child.
469 0           p_i--;
470             }
471             // Root of tree is always black
472 0 0         if (rbhash[path->refs[0]] & 1)
473 0           rbhash[path->refs[0]] ^= 1;
474             #if !POLLFD_RBHASH_RUN_WITH_SCISSORS
475             // Path is no longer valid, because rotations may have destroyed it.
476 0           path->len= 0;
477             #endif
478 0           return node_id;
479             }
480              
481             /* Delete a node at the end of a path. The path must end with a non-Sentinel
482             * reference, and must also be allocated to the maximum height of the tree,
483             * because the node you want to delete might need to be replaced by a node
484             * deeper in the tree. The tree will be re-balanced using the Red/Black
485             * algorithm. If this is the last node in the tree, it clears the hash bucket.
486             *
487             * The path is destroyed in the process, as rotations and node-replacement
488             * occur. You may not use the path afterward, even if the function fails.
489             * (the path could be updated during balance rotations, but would add
490             * overhead and users are unlikely to need it afterward anyway)
491             *
492             * Returns the deleted node_id on success, or 0 on an assertion failure if
493             * you disabled assertions.
494             */
495 0           extern size_t pollfd_rbhash_path_delete_8(uint8_t *rbhash, pollfd_rbhash_path *path) {
496             // See pollfd_rbhash_path_insert for the notes on the bitwise operations
497             uint8_t pos, ch1, ch2, sibling;
498 0           int p_i= path->len-1, p_lim= path->lim;
499 0           size_t *parent_refs= path->refs, ref, pos_ref;
500             // Path should be at least 1 element (the bucket root ref)
501 0 0         POLLFD_RBHASH_ASSERT(path->len >= 1);
502             // Read the final ref to find 'pos_ref' and 'pos'
503 0           pos_ref= parent_refs[p_i];
504 0           pos= rbhash[pos_ref];
505             // Path must point to a non-sentinel node
506 0 0         POLLFD_RBHASH_ASSERT(pos != 0);
507             // If pos has children, find a leaf to swap with.
508             // Then delete this node in the leaf's position.
509             // Note that normal red/black would delete the element first, then swap, but if we do that
510             // a rotation could change the path->refs putting the node-to-delete somwhere else.
511 0           ch1= rbhash[pos], ch2= rbhash[pos ^ 1];
512 0 0         if (ch1 || ch2) {
    0          
513 0 0         if (ch1 && ch2) {
    0          
514 0           int orig_p_i= p_i;
515 0           uint8_t alt= pos, alt2;
516             // Descend one level to the left.
517             // The path should always have room for this additional reference if it
518             // was allocated to max-tree-height and the tree is actually balanced.
519 0           ++p_i;
520 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
521 0           parent_refs[p_i]= ref= (pos >> 1 << 1); // go left;
522 0           alt= rbhash[ref]; // either ch1 or ch2, but now we know it's the left one
523             // descend as many levels as possible to the right
524 0 0         while ((alt= rbhash[ref= alt | 1])) {
525 0           ++p_i;
526 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
527 0           parent_refs[p_i]= ref;
528             }
529             // 'alt' is the node we swap with.
530 0           alt= rbhash[parent_refs[p_i]];
531             // is there one to the left?
532 0 0         if ((alt2= rbhash[(alt >> 1 << 1)])) {
533 0 0         POLLFD_RBHASH_ASSERT(alt2 & 1);
534             // it is required to be a red leaf, so replace alt with it
535 0           rbhash[parent_refs[p_i]]= alt2 ^ 1;
536 0           ((uint16_t *)rbhash)[alt2 >> 1]= 0;
537             // Now substitute this for pos and we're done.
538 0           ((uint16_t *)rbhash)[alt >> 1]= ((uint16_t *)rbhash)[pos >> 1];
539 0           rbhash[pos_ref]= (alt >> 1 << 1) | (pos & 1); // preserve color of pos
540 0           goto done;
541             }
542             else {
543             // swap colors of alt and pos
544 0           alt ^= pos & 1;
545 0           pos ^= alt & 1;
546 0           alt ^= pos & 1;
547 0           ((uint16_t *)rbhash)[alt >> 1]= ((uint16_t *)rbhash)[pos >> 1];
548 0           rbhash[pos_ref]= alt;
549             // the parent ref at orig_p_i+1 just changed address, so update that
550             // (and this affects the next line if alt was a child of pos)
551 0           parent_refs[orig_p_i + 1]= (alt >> 1 << 1); // was left branch at that point
552 0           pos_ref= parent_refs[p_i];
553             }
554             }
555             else {
556             // Node is black with one child. Swap with it.
557 0           rbhash[pos_ref]= ((ch1 | ch2) >> 1 << 1); // and make it black
558 0           goto done;
559             }
560             }
561             // Remove it.
562 0           rbhash[pos_ref]= 0;
563             // It was a black node with no children. Now it gets interesting.
564 0 0         if (!(pos & 1)) {
565             // The tree must have the same number of black nodes along any path from root
566             // to leaf. We want to remove a black node, disrupting the number of black
567             // nodes along the path from the root to the current leaf. To correct this,
568             // we must either reduce all other paths, or add a black node to the current
569             // path.
570             // Loop until the current node is red, or until we get to the root node.
571 0           sibling= rbhash[pos_ref ^ 1];
572 0           --p_i; // p_i is now the index of the ref to the parent
573 0 0         while (p_i >= 0) {
574             size_t near_nephew_ref;
575             uint8_t near_nephew;
576             // If the sibling is red, we are unable to reduce the number of black
577             // nodes in the sibling tree, and we can't increase the number of black
578             // nodes in our tree.. Thus we must do a rotation from the sibling
579             // tree to our tree to give us some extra (red) nodes to play with.
580             // This is Case 1 from the text
581 0 0         if (sibling & 1) {
582             // Node is black and sibling is red. Get ref to sibling's near subtree
583 0           near_nephew_ref= (sibling ^ 1) | (pos_ref & 1);
584             // sibling is new parent, and now black.
585 0           rbhash[parent_refs[p_i]]= sibling ^ 1;
586             // move sibling's child under parent, becoming new sibling (which is black)
587 0           sibling= rbhash[near_nephew_ref];
588 0           rbhash[pos_ref ^ 1]= sibling;
589 0           rbhash[near_nephew_ref]= pos_ref | 1; // former sibling sameside tree = parent, now red
590 0           ++p_i;
591 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
592 0           parent_refs[p_i] = near_nephew_ref; // insert new parent into list
593             }
594             // sibling will be black here
595              
596             // If the sibling is black and both children are black, we have to
597             // reduce the black node count in the sibling's tree to match ours.
598             // This is Case 2a from the text.
599 0           near_nephew_ref= sibling | (pos_ref & 1);
600 0           near_nephew= rbhash[near_nephew_ref];
601 0 0         if (!((near_nephew|rbhash[near_nephew_ref ^ 1]) & 1)) {
602 0 0         POLLFD_RBHASH_ASSERT(sibling > 1);
603 0           rbhash[pos_ref ^ 1] |= 1; // change sibling to red
604             // Now we move one level up the tree to continue fixing the other branches
605 0 0         if (p_i < 1)
606 0           break;
607 0           pos_ref= parent_refs[p_i--];
608 0 0         if (rbhash[pos_ref] & 1) {
609             // Now, make the current node black (to fulfill Case 2b)
610 0           rbhash[pos_ref] ^= 1;
611 0           break;
612             }
613 0           sibling= rbhash[pos_ref ^ 1];
614             }
615             else {
616             // sibling will be black with 1 or 2 red children here
617              
618             // If one of the sibling's children are red, we again can't make the
619             // sibling red to balance the tree at the parent, so we have to do a
620             // rotation. If the "near" nephew is red and the "far" nephew is
621             // black, we need to rotate that tree away before rotating the
622             // parent toward.
623             // After doing a rotation and rearranging a few colors, the effect is
624             // that we maintain the same number of black nodes per path on the far
625             // side of the parent, and we gain a black node on the current side,
626             // so we are done.
627 0 0         if (near_nephew & 1) {
628             // Case 3 from the text, double rotation
629 0           size_t tmp_ref= near_nephew ^ (pos_ref & 1); // near nephew's far child
630 0           rbhash[near_nephew_ref]= rbhash[tmp_ref];
631 0           rbhash[pos_ref ^ 1]= near_nephew;
632 0           rbhash[tmp_ref]= sibling;
633 0           sibling= near_nephew ^ 1; // make it black
634 0           near_nephew_ref= sibling | (pos_ref & 1);
635             }
636             else
637 0           rbhash[near_nephew_ref ^ 1] ^= 1; // far nephew becomes black
638             // now Case 4 from the text
639 0 0         POLLFD_RBHASH_ASSERT(sibling > 1);
640 0           rbhash[pos_ref ^ 1]= rbhash[near_nephew_ref];
641             // parent becomes black, balancing current path
642 0           rbhash[near_nephew_ref]= (pos_ref >> 1 << 1);
643             // Sibling assumes parent's color and position
644 0           rbhash[parent_refs[p_i]]= sibling | (rbhash[parent_refs[p_i]] & 1);
645 0           break;
646             }
647             }
648             }
649 0           done:
650             // Ensure root-ref is black
651 0 0         if (rbhash[parent_refs[0]] & 1)
652 0           rbhash[parent_refs[0]] ^= 1;
653             // clean the 'pos' node for future use
654 0           ((uint16_t *)rbhash)[pos >> 1]= 0;
655             #if !POLLFD_RBHASH_RUN_WITH_SCISSORS
656             // Path is no longer valid, because rotations may have destroyed it.
657 0           path->len= 0;
658             #endif
659 0           return pos >> 1;
660             }
661 0           extern size_t pollfd_rbhash_path_delete_16(uint16_t *rbhash, pollfd_rbhash_path *path) {
662             // See pollfd_rbhash_path_insert for the notes on the bitwise operations
663             uint16_t pos, ch1, ch2, sibling;
664 0           int p_i= path->len-1, p_lim= path->lim;
665 0           size_t *parent_refs= path->refs, ref, pos_ref;
666             // Path should be at least 1 element (the bucket root ref)
667 0 0         POLLFD_RBHASH_ASSERT(path->len >= 1);
668             // Read the final ref to find 'pos_ref' and 'pos'
669 0           pos_ref= parent_refs[p_i];
670 0           pos= rbhash[pos_ref];
671             // Path must point to a non-sentinel node
672 0 0         POLLFD_RBHASH_ASSERT(pos != 0);
673             // If pos has children, find a leaf to swap with.
674             // Then delete this node in the leaf's position.
675             // Note that normal red/black would delete the element first, then swap, but if we do that
676             // a rotation could change the path->refs putting the node-to-delete somwhere else.
677 0           ch1= rbhash[pos], ch2= rbhash[pos ^ 1];
678 0 0         if (ch1 || ch2) {
    0          
679 0 0         if (ch1 && ch2) {
    0          
680 0           int orig_p_i= p_i;
681 0           uint16_t alt= pos, alt2;
682             // Descend one level to the left.
683             // The path should always have room for this additional reference if it
684             // was allocated to max-tree-height and the tree is actually balanced.
685 0           ++p_i;
686 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
687 0           parent_refs[p_i]= ref= (pos >> 1 << 1); // go left;
688 0           alt= rbhash[ref]; // either ch1 or ch2, but now we know it's the left one
689             // descend as many levels as possible to the right
690 0 0         while ((alt= rbhash[ref= alt | 1])) {
691 0           ++p_i;
692 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
693 0           parent_refs[p_i]= ref;
694             }
695             // 'alt' is the node we swap with.
696 0           alt= rbhash[parent_refs[p_i]];
697             // is there one to the left?
698 0 0         if ((alt2= rbhash[(alt >> 1 << 1)])) {
699 0 0         POLLFD_RBHASH_ASSERT(alt2 & 1);
700             // it is required to be a red leaf, so replace alt with it
701 0           rbhash[parent_refs[p_i]]= alt2 ^ 1;
702 0           ((uint32_t *)rbhash)[alt2 >> 1]= 0;
703             // Now substitute this for pos and we're done.
704 0           ((uint32_t *)rbhash)[alt >> 1]= ((uint32_t *)rbhash)[pos >> 1];
705 0           rbhash[pos_ref]= (alt >> 1 << 1) | (pos & 1); // preserve color of pos
706 0           goto done;
707             }
708             else {
709             // swap colors of alt and pos
710 0           alt ^= pos & 1;
711 0           pos ^= alt & 1;
712 0           alt ^= pos & 1;
713 0           ((uint32_t *)rbhash)[alt >> 1]= ((uint32_t *)rbhash)[pos >> 1];
714 0           rbhash[pos_ref]= alt;
715             // the parent ref at orig_p_i+1 just changed address, so update that
716             // (and this affects the next line if alt was a child of pos)
717 0           parent_refs[orig_p_i + 1]= (alt >> 1 << 1); // was left branch at that point
718 0           pos_ref= parent_refs[p_i];
719             }
720             }
721             else {
722             // Node is black with one child. Swap with it.
723 0           rbhash[pos_ref]= ((ch1 | ch2) >> 1 << 1); // and make it black
724 0           goto done;
725             }
726             }
727             // Remove it.
728 0           rbhash[pos_ref]= 0;
729             // It was a black node with no children. Now it gets interesting.
730 0 0         if (!(pos & 1)) {
731             // The tree must have the same number of black nodes along any path from root
732             // to leaf. We want to remove a black node, disrupting the number of black
733             // nodes along the path from the root to the current leaf. To correct this,
734             // we must either reduce all other paths, or add a black node to the current
735             // path.
736             // Loop until the current node is red, or until we get to the root node.
737 0           sibling= rbhash[pos_ref ^ 1];
738 0           --p_i; // p_i is now the index of the ref to the parent
739 0 0         while (p_i >= 0) {
740             size_t near_nephew_ref;
741             uint16_t near_nephew;
742             // If the sibling is red, we are unable to reduce the number of black
743             // nodes in the sibling tree, and we can't increase the number of black
744             // nodes in our tree.. Thus we must do a rotation from the sibling
745             // tree to our tree to give us some extra (red) nodes to play with.
746             // This is Case 1 from the text
747 0 0         if (sibling & 1) {
748             // Node is black and sibling is red. Get ref to sibling's near subtree
749 0           near_nephew_ref= (sibling ^ 1) | (pos_ref & 1);
750             // sibling is new parent, and now black.
751 0           rbhash[parent_refs[p_i]]= sibling ^ 1;
752             // move sibling's child under parent, becoming new sibling (which is black)
753 0           sibling= rbhash[near_nephew_ref];
754 0           rbhash[pos_ref ^ 1]= sibling;
755 0           rbhash[near_nephew_ref]= pos_ref | 1; // former sibling sameside tree = parent, now red
756 0           ++p_i;
757 0 0         POLLFD_RBHASH_ASSERT(p_i < p_lim);
758 0           parent_refs[p_i] = near_nephew_ref; // insert new parent into list
759             }
760             // sibling will be black here
761              
762             // If the sibling is black and both children are black, we have to
763             // reduce the black node count in the sibling's tree to match ours.
764             // This is Case 2a from the text.
765 0           near_nephew_ref= sibling | (pos_ref & 1);
766 0           near_nephew= rbhash[near_nephew_ref];
767 0 0         if (!((near_nephew|rbhash[near_nephew_ref ^ 1]) & 1)) {
768 0 0         POLLFD_RBHASH_ASSERT(sibling > 1);
769 0           rbhash[pos_ref ^ 1] |= 1; // change sibling to red
770             // Now we move one level up the tree to continue fixing the other branches
771 0 0         if (p_i < 1)
772 0           break;
773 0           pos_ref= parent_refs[p_i--];
774 0 0         if (rbhash[pos_ref] & 1) {
775             // Now, make the current node black (to fulfill Case 2b)
776 0           rbhash[pos_ref] ^= 1;
777 0           break;
778             }
779 0           sibling= rbhash[pos_ref ^ 1];
780             }
781             else {
782             // sibling will be black with 1 or 2 red children here
783              
784             // If one of the sibling's children are red, we again can't make the
785             // sibling red to balance the tree at the parent, so we have to do a
786             // rotation. If the "near" nephew is red and the "far" nephew is
787             // black, we need to rotate that tree away before rotating the
788             // parent toward.
789             // After doing a rotation and rearranging a few colors, the effect is
790             // that we maintain the same number of black nodes per path on the far
791             // side of the parent, and we gain a black node on the current side,
792             // so we are done.
793 0 0         if (near_nephew & 1) {
794             // Case 3 from the text, double rotation
795 0           size_t tmp_ref= near_nephew ^ (pos_ref & 1); // near nephew's far child
796 0           rbhash[near_nephew_ref]= rbhash[tmp_ref];
797 0           rbhash[pos_ref ^ 1]= near_nephew;
798 0           rbhash[tmp_ref]= sibling;
799 0           sibling= near_nephew ^ 1; // make it black
800 0           near_nephew_ref= sibling | (pos_ref & 1);
801             }
802             else
803 0           rbhash[near_nephew_ref ^ 1] ^= 1; // far nephew becomes black
804             // now Case 4 from the text
805 0 0         POLLFD_RBHASH_ASSERT(sibling > 1);
806 0           rbhash[pos_ref ^ 1]= rbhash[near_nephew_ref];
807             // parent becomes black, balancing current path
808 0           rbhash[near_nephew_ref]= (pos_ref >> 1 << 1);
809             // Sibling assumes parent's color and position
810 0           rbhash[parent_refs[p_i]]= sibling | (rbhash[parent_refs[p_i]] & 1);
811 0           break;
812             }
813             }
814             }
815 0           done:
816             // Ensure root-ref is black
817 0 0         if (rbhash[parent_refs[0]] & 1)
818 0           rbhash[parent_refs[0]] ^= 1;
819             // clean the 'pos' node for future use
820 0           ((uint32_t *)rbhash)[pos >> 1]= 0;
821             #if !POLLFD_RBHASH_RUN_WITH_SCISSORS
822             // Path is no longer valid, because rotations may have destroyed it.
823 0           path->len= 0;
824             #endif
825 0           return pos >> 1;
826             }
827             // Handy for gdb: "p pollfd_rbhash_treeprint_8(rbhash, capacity, i, i, NULL, NULL, stdout)"
828 0           static size_t pollfd_rbhash_print_tree_8(
829             uint8_t *rbhash, uint8_t max_node, uint8_t node, uint8_t mark_node,
830             void (*print_node)(void*,size_t,FILE*), void* userdata, FILE * out
831             ) {
832             uint8_t node_path[ 1+POLLFD_RBHASH_MAX_TREE_HEIGHT_8 ];
833             bool cycle;
834 0           int i, pos, step= 0;
835 0           size_t nodecount= 0;
836 0 0         if (!node) {
837 0           fputs("(empty tree)\n", out);
838 0           return 0;
839             }
840 0           node_path[0]= 0;
841 0           node_path[pos= 1]= node << 1;
842 0 0         while (node && pos) {
    0          
843 0           switch (step) {
844 0           case 0:
845             // Check for cycles
846 0           cycle= false;
847 0 0         for (i= 1; i < pos; i++)
848 0 0         if ((node_path[i]>>1) == (node_path[pos]>>1))
849 0           cycle= true;
850            
851             // Proceed down right subtree if possible
852 0 0         if (!cycle && pos < POLLFD_RBHASH_MAX_TREE_HEIGHT_8
    0          
853 0 0         && node <= max_node && rbhash[(node<<1)|1]
    0          
854             ) {
855 0           node= rbhash[(node<<1)|1] >> 1;
856 0           node_path[++pos]= node << 1;
857 0           continue;
858             }
859             case 1:
860             // Print tree branches for nodes up until this one
861 0 0         for (i= 2; i < pos; i++)
862 0 0         fputs((node_path[i]&1) == (node_path[i+1]&1)? " " : " |", out);
863 0 0         if (pos > 1)
864 0 0         fputs((node_path[pos]&1)? " `" : " ,", out);
865            
866             // Print content of this node
867 0 0         fprintf(out, "--%c%c%c #%ld%s ",
    0          
    0          
    0          
868             (node == mark_node? '(' : '-'),
869 0 0         (node > max_node? '!' : (rbhash[ (node_path[pos-1]|1) ^ (node_path[pos]&1) ]&1)? 'R':'B'),
870             (node == mark_node? ')' : ' '),
871             (long) node,
872             cycle? " CYCLE DETECTED"
873             : pos >= POLLFD_RBHASH_MAX_TREE_HEIGHT_8? " MAX DEPTH EXCEEDED"
874 0 0         : node > max_node? " VALUE OUT OF BOUNDS"
875 0 0         : ""
876             );
877 0 0         if (print_node) print_node(userdata, node, out);
878 0           fputs("\n", out);
879 0           ++nodecount;
880            
881             // Proceed down left subtree if possible
882 0 0         if (!cycle && pos < POLLFD_RBHASH_MAX_TREE_HEIGHT_8
    0          
883 0 0         && node <= max_node && rbhash[node<<1]
    0          
884             ) {
885 0           node= rbhash[node<<1] >> 1;
886 0           node_path[++pos]= (node << 1) | 1;
887 0           step= 0;
888 0           continue;
889             }
890             case 2:
891             // Return to parent
892 0           step= (node_path[pos]&1) + 1;
893 0           node= node_path[--pos] >> 1;
894 0           cycle= false;
895             }
896             }
897 0           return nodecount;
898             }
899             // Handy for gdb: "p pollfd_rbhash_treeprint_16(rbhash, capacity, i, i, NULL, NULL, stdout)"
900 0           static size_t pollfd_rbhash_print_tree_16(
901             uint16_t *rbhash, uint16_t max_node, uint16_t node, uint16_t mark_node,
902             void (*print_node)(void*,size_t,FILE*), void* userdata, FILE * out
903             ) {
904             uint16_t node_path[ 1+POLLFD_RBHASH_MAX_TREE_HEIGHT_16 ];
905             bool cycle;
906 0           int i, pos, step= 0;
907 0           size_t nodecount= 0;
908 0 0         if (!node) {
909 0           fputs("(empty tree)\n", out);
910 0           return 0;
911             }
912 0           node_path[0]= 0;
913 0           node_path[pos= 1]= node << 1;
914 0 0         while (node && pos) {
    0          
915 0           switch (step) {
916 0           case 0:
917             // Check for cycles
918 0           cycle= false;
919 0 0         for (i= 1; i < pos; i++)
920 0 0         if ((node_path[i]>>1) == (node_path[pos]>>1))
921 0           cycle= true;
922            
923             // Proceed down right subtree if possible
924 0 0         if (!cycle && pos < POLLFD_RBHASH_MAX_TREE_HEIGHT_16
    0          
925 0 0         && node <= max_node && rbhash[(node<<1)|1]
    0          
926             ) {
927 0           node= rbhash[(node<<1)|1] >> 1;
928 0           node_path[++pos]= node << 1;
929 0           continue;
930             }
931             case 1:
932             // Print tree branches for nodes up until this one
933 0 0         for (i= 2; i < pos; i++)
934 0 0         fputs((node_path[i]&1) == (node_path[i+1]&1)? " " : " |", out);
935 0 0         if (pos > 1)
936 0 0         fputs((node_path[pos]&1)? " `" : " ,", out);
937            
938             // Print content of this node
939 0 0         fprintf(out, "--%c%c%c #%ld%s ",
    0          
    0          
    0          
940             (node == mark_node? '(' : '-'),
941 0 0         (node > max_node? '!' : (rbhash[ (node_path[pos-1]|1) ^ (node_path[pos]&1) ]&1)? 'R':'B'),
942             (node == mark_node? ')' : ' '),
943             (long) node,
944             cycle? " CYCLE DETECTED"
945             : pos >= POLLFD_RBHASH_MAX_TREE_HEIGHT_16? " MAX DEPTH EXCEEDED"
946 0 0         : node > max_node? " VALUE OUT OF BOUNDS"
947 0 0         : ""
948             );
949 0 0         if (print_node) print_node(userdata, node, out);
950 0           fputs("\n", out);
951 0           ++nodecount;
952            
953             // Proceed down left subtree if possible
954 0 0         if (!cycle && pos < POLLFD_RBHASH_MAX_TREE_HEIGHT_16
    0          
955 0 0         && node <= max_node && rbhash[node<<1]
    0          
956             ) {
957 0           node= rbhash[node<<1] >> 1;
958 0           node_path[++pos]= (node << 1) | 1;
959 0           step= 0;
960 0           continue;
961             }
962             case 2:
963             // Return to parent
964 0           step= (node_path[pos]&1) + 1;
965 0           node= node_path[--pos] >> 1;
966 0           cycle= false;
967             }
968             }
969 0           return nodecount;
970             }
971              
972 0           void pollfd_rbhash_print(
973             void *rbhash, size_t capacity, size_t n_buckets,
974             void (*print_node)(void*,size_t,FILE*), void* userdata, FILE *out
975             ) {
976 0           size_t used= 0, collision= 0, empty=0, i;
977 0           fprintf(out, "# rbhash for capacity=%ld: %ld hash buckets, %ld bytes\n"
978             "--------------------\n",
979 0 0         (long) capacity, (long) n_buckets, (long) POLLFD_RBHASH_SIZEOF(capacity, n_buckets));
980 0 0         if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8) {
981 0           uint8_t *nodes= (uint8_t*) rbhash;
982 0           uint8_t *table= nodes + POLLFD_RBHASH_TABLE_WORD_OFS(capacity);
983 0 0         for (i= 0; i < n_buckets; i++) {
984 0 0         if (table[i]) {
985 0 0         if (empty) {
986 0           fprintf(out, "(%ld empty buckets)\n", (long) empty);
987 0           empty= 0;
988             }
989 0           ++used;
990 0           collision += pollfd_rbhash_print_tree_8(rbhash, capacity, table[i]>>1, 0, print_node, userdata, out) - 1;
991             } else
992 0           ++empty;
993             }
994 0 0         if (empty) {
995 0           fprintf(out, "(%ld empty buckets)\n", (long) empty);
996 0           empty= 0;
997             }
998             }
999 0 0         else if (capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16) {
1000 0           uint16_t *nodes= (uint16_t*) rbhash;
1001 0           uint16_t *table= nodes + POLLFD_RBHASH_TABLE_WORD_OFS(capacity);
1002 0 0         for (i= 0; i < n_buckets; i++) {
1003 0 0         if (table[i]) {
1004 0 0         if (empty) {
1005 0           fprintf(out, "(%ld empty buckets)\n", (long) empty);
1006 0           empty= 0;
1007             }
1008 0           ++used;
1009 0           collision += pollfd_rbhash_print_tree_16(rbhash, capacity, table[i]>>1, 0, print_node, userdata, out) - 1;
1010             } else
1011 0           ++empty;
1012             }
1013 0 0         if (empty) {
1014 0           fprintf(out, "(%ld empty buckets)\n", (long) empty);
1015 0           empty= 0;
1016             }
1017             }
1018 0           fprintf(out, "--------------------\n"
1019             "# used %ld/%ld buckets, %ld collisions\n",
1020             (long) used, (long) n_buckets, (long) collision);
1021 0           }