-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpollfd_rbhash.h
138 lines (113 loc) · 5.74 KB
/
pollfd_rbhash.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#ifndef POLLFD_RBHASH_H
#define POLLFD_RBHASH_H
/*
Generated by rbhash.cpppp using command
cpppp -p 'max_bits=16' \
-p 'namespace=pollfd_rbhash' \
-p '@default_search_args=('\''int search_fd'\'')' \
-p 'default_search_cmp=search_fd - ((struct pollfd*)rbhash)[(int)node_id-1-(int)capacity].fd' \
rbhash.cpppp \
-o 'public=pollfd_rbhash.h' \
-o pollfd_rbhash.c
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
/* MAX_TREE_HEIGHT is the maximum number of nodes from root to leaf in any
* correctly balanced tree. The exact formula for the maximum height (including
* root node) is floor(2*log2(N/2+1)) for a tree of N nodes.
*/
#define POLLFD_RBHASH_MAX_ELEMENTS_8 0x7F
#define POLLFD_RBHASH_MAX_TREE_HEIGHT_8 12
#define POLLFD_RBHASH_MAX_ELEMENTS_16 0x7FFF
#define POLLFD_RBHASH_MAX_TREE_HEIGHT_16 28
/* This macro tells you the word offset (treating rbhash as an array of words)
* of the first hash bucket.
*/
#define POLLFD_RBHASH_TABLE_WORD_OFS(capacity) ( (capacity)*2 + 2 )
/* This macro selects the word size needed to index 'capacity' number of
* user elements.
*/
#define POLLFD_RBHASH_SIZEOF_WORD(capacity) ( \
(capacity) <= POLLFD_RBHASH_MAX_ELEMENTS_8? 1 : \
2 \
)
/* This macro defines the total size (in bytes) of the rbhash storage
* for a given number of elements and buckets. This does not include
* the user's elements themselves, since those are whatever size the
* user wants them to be, and rbhash doesn't need to know.
*/
#define POLLFD_RBHASH_SIZEOF(capacity, buckets) ( \
POLLFD_RBHASH_SIZEOF_WORD(capacity) \
* ( POLLFD_RBHASH_TABLE_WORD_OFS(capacity) + buckets ) \
)
/* Several functions can operate on a "path", which is a list of
* references starting at the bucket and ending at a tree node.
* The path is allocated to the maximum depth that a tree of that
* word-bits-size could reach. Since this drastically affects the
* amount of stack used, a struct is declared for each word-bit size.
*
* The structs each record their length so that they can be passed
* interchangably to the functions. You could even allocate custom
* lengths with alloca, but that seems overcomplicated.
*/
struct pollfd_rbhash_path_8 {
uint8_t len, lim;
size_t refs[POLLFD_RBHASH_MAX_TREE_HEIGHT_8];
};
inline void pollfd_rbhash_path_8_init(struct pollfd_rbhash_path_8 *p) {
p->len= 0;
p->lim= POLLFD_RBHASH_MAX_TREE_HEIGHT_8;
}
struct pollfd_rbhash_path_16 {
uint8_t len, lim;
size_t refs[POLLFD_RBHASH_MAX_TREE_HEIGHT_16];
};
inline void pollfd_rbhash_path_16_init(struct pollfd_rbhash_path_16 *p) {
p->len= 0;
p->lim= POLLFD_RBHASH_MAX_TREE_HEIGHT_16;
}
// Different template output may end up with different structs claiming
// the name of pollfd_rbhash_path, but that should be OK.
typedef struct pollfd_rbhash_path_16 pollfd_rbhash_path;
#define pollfd_rbhash_path_init(p) pollfd_rbhash_path_16_init(p)
// Iterate one or more places through the R/B tree of a bucket, updating 'path'
extern size_t pollfd_rbhash_path_step(void *rbhash, size_t capacity, pollfd_rbhash_path *path, int ofs);
// Exchange the tree node of one node_id (at the end of 'path') for another node_id
extern size_t pollfd_rbhash_path_swap(void *rbhash, size_t capacity, pollfd_rbhash_path *path, size_t new_node_id);
// implementation detail used to reduce size of inline functions
extern size_t pollfd_rbhash_capacity_bounds_assertion(size_t capacity);
// Add a node_id at the end of 'path', and balance the tree if needed
extern size_t pollfd_rbhash_path_insert_8(uint8_t *rbhash, pollfd_rbhash_path *path, size_t node_id);
extern size_t pollfd_rbhash_path_insert_16(uint16_t *rbhash, pollfd_rbhash_path *path, size_t node_id);
inline size_t pollfd_rbhash_path_insert(void *rbhash, size_t capacity, pollfd_rbhash_path *path, size_t node) {
return
(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8)? pollfd_rbhash_path_insert_8((uint8_t*) rbhash, path, node) :
(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16)? pollfd_rbhash_path_insert_16((uint16_t*) rbhash, path, node) :
pollfd_rbhash_capacity_bounds_assertion(capacity);
}
// Remove the node_id from the end of 'path', and balance the tree if needed
extern size_t pollfd_rbhash_path_delete_8(uint8_t *rbhash, pollfd_rbhash_path *path);
extern size_t pollfd_rbhash_path_delete_16(uint16_t *rbhash, pollfd_rbhash_path *path);
inline size_t pollfd_rbhash_path_delete(void *rbhash, size_t capacity, pollfd_rbhash_path *path) {
return
(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_8)? pollfd_rbhash_path_delete_8((uint8_t*) rbhash, path) :
(capacity <= POLLFD_RBHASH_MAX_ELEMENTS_16)? pollfd_rbhash_path_delete_16((uint16_t*) rbhash, path) :
pollfd_rbhash_capacity_bounds_assertion(capacity);
}
// Find a node_id matching the search criteria and fill in the 'path' to it, else return 0
extern size_t pollfd_rbhash_find_path(void *rbhash, size_t capacity, pollfd_rbhash_path *path, size_t bucket_idx, int search_fd);
// Simplified search for node_id, without building a path
extern size_t pollfd_rbhash_find(void *rbhash, size_t capacity, size_t bucket_idx, int search_fd);
// Insert a node_id, unless one already matches the search criteria
extern size_t pollfd_rbhash_insert(void *rbhash, size_t capacity, size_t node_id, size_t bucket_idx, int search_fd);
// Delete a node matching the search criteria
extern size_t pollfd_rbhash_delete(void *rbhash, size_t capacity, size_t bucket_idx, int search_fd);
// Handy for gdb:
// p pollfd_rbhash_print(rbhash, capacity, buckets, NULL, NULL, stdout)
extern void pollfd_rbhash_print(void *rbhash, size_t capacity, size_t n_buckets,
void (*print_node)(void*,size_t,FILE*), void* userdata, FILE *out);
#endif