Coverage Report

Created: 2023-03-26 07:41

/src/openvswitch/lib/hindex.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2013, 2016 Nicira, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#ifndef HINDEX_H
18
#define HINDEX_H 1
19
20
/* Hashed multimap.
21
 *
22
 * hindex is a hash table data structure that gracefully handles duplicates.
23
 * With a high-quality hash function, insertion, deletion, and search are O(1)
24
 * expected time, regardless of the number of duplicates for a given key.  */
25
26
#include <stdbool.h>
27
#include <stdlib.h>
28
#include "util.h"
29
30
/* A hash index node, to embed inside the data structure being indexed.
31
 *
32
 * Nodes are linked together like this (the boxes are labeled with hash
33
 * values):
34
 *
35
 *             +--------+ d   +--------+ d   +--------+ d
36
 *  bucket---> |    6   |---->|   20   |---->|   15   |---->null
37
 *             +-|------+     +-|------+     +-|------+
38
 *               |    ^         |              |    ^
39
 *              s|    |d        |s            s|    |d
40
 *               V    |         V              V    |
41
 *             +------|-+      null          +------|-+
42
 *             |    6   |                    |   15   |
43
 *             +-|------+                    +-|------+
44
 *               |    ^                        |
45
 *              s|    |d                      s|
46
 *               V    |                        V
47
 *             +------|-+                     null
48
 *             |    6   |
49
 *             +-|------+
50
 *               |
51
 *              s|
52
 *               V
53
 *              null
54
 *
55
 * The basic usage is:
56
 *
57
 *     - To visit the unique hash values in the hindex, follow the 'd'
58
 *       ("different") pointers starting from each bucket.  The nodes visited
59
 *       this way are called "head" nodes, because they are at the head of the
60
 *       vertical chains.
61
 *
62
 *     - To visit the nodes with hash value H, follow the 'd' pointers in the
63
 *       appropriate bucket until you find one with hash H, then follow the 's'
64
 *       ("same") pointers until you hit a null pointer.  The non-head nodes
65
 *       visited this way are called "body" nodes.
66
 *
67
 *     - The 'd' pointers in body nodes point back to the previous body node
68
 *       or, for the first body node, to the head node.  (This makes it
69
 *       possible to remove a body node without traversing all the way downward
70
 *       from the head).
71
 */
72
struct hindex_node {
73
    /* Hash value. */
74
    size_t hash;
75
76
    /* In a head node, the next head node (with a hash different from this
77
     * node), or NULL if this is the last node in this bucket.
78
     *
79
     * In a body node, the previous head or body node (with the same hash as
80
     * this node).  Never null. */
81
    struct hindex_node *d;
82
83
    /* In a head or a body node, the next body node with the same hash as this
84
     * node.  NULL if this is the last node with this hash. */
85
    struct hindex_node *s;
86
};
87
88
/* A hash index. */
89
struct hindex {
90
    struct hindex_node **buckets; /* Must point to 'one' iff 'mask' == 0. */
91
    struct hindex_node *one;
92
    size_t mask;      /* 0 or more lowest-order bits set, others cleared. */
93
    size_t n_unique;  /* Number of unique hashes (the number of head nodes). */
94
};
95
96
/* Initializer for an empty hash index. */
97
#define HINDEX_INITIALIZER(HINDEX) \
98
    { (struct hindex_node **const) &(HINDEX)->one, NULL, 0, 0 }
99
100
/* Initialization. */
101
void hindex_init(struct hindex *);
102
void hindex_destroy(struct hindex *);
103
void hindex_clear(struct hindex *);
104
void hindex_swap(struct hindex *a, struct hindex *b);
105
void hindex_moved(struct hindex *hindex);
106
static inline bool hindex_is_empty(const struct hindex *);
107
108
/* Adjusting capacity. */
109
void hindex_expand(struct hindex *);
110
void hindex_shrink(struct hindex *);
111
void hindex_reserve(struct hindex *, size_t capacity);
112
113
/* Insertion and deletion. */
114
void hindex_insert_fast(struct hindex *, struct hindex_node *, size_t hash);
115
void hindex_insert(struct hindex *, struct hindex_node *, size_t hash);
116
void hindex_remove(struct hindex *, struct hindex_node *);
117
118
/* Search.
119
 *
120
 * HINDEX_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HINDEX that
121
 * have hash value equal to HASH.  MEMBER must be the name of the 'struct
122
 * hindex_node' member within NODE.
123
 *
124
 * The loop should not change NODE to point to a different node or insert or
125
 * delete nodes in HINDEX (unless it "break"s out of the loop to terminate
126
 * iteration).
127
 *
128
 * Evaluates HASH only once.
129
 */
130
#define HINDEX_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HINDEX)               \
131
0
    for (INIT_MULTIVAR(NODE, MEMBER, hindex_node_with_hash(HINDEX, HASH),   \
132
0
                       struct hindex_node);                                 \
133
0
         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);          \
134
0
         UPDATE_MULTIVAR(NODE, ITER_VAR(NODE)->s))
135
136
/* Safe when NODE may be freed (not needed when NODE may be removed from the
137
 * hash map but its members remain accessible and intact). */
138
#define HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG(NODE, NEXT, MEMBER, HASH, HINDEX) \
139
    for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                          \
140
                                hindex_node_with_hash(HINDEX, HASH),          \
141
                                struct hindex_node);                          \
142
         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                     \
143
                                      ITER_VAR(NODE) != NULL,                 \
144
                                      ITER_VAR(NEXT) = ITER_VAR(NODE)->s,     \
145
                                      ITER_VAR(NEXT) != NULL);                \
146
         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
147
148
/* Short version of HINDEX_FOR_EACH_WITH_HASH_SAFE. */
149
#define HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT(NODE, MEMBER, HASH, HINDEX)      \
150
0
    for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER,                               \
151
0
                            hindex_node_with_hash(HINDEX, HASH),              \
152
0
                            struct hindex_node);                              \
153
0
         CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER,                          \
154
0
                                       ITER_VAR(NODE) != NULL,                \
155
0
                                 ITER_NEXT_VAR(NODE) = ITER_VAR(NODE)->s);    \
156
0
         UPDATE_MULTIVAR_SAFE_SHORT(NODE))
157
158
#define HINDEX_FOR_EACH_WITH_HASH_SAFE(...)                                   \
159
0
    OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_WITH_HASH_SAFE_LONG,                  \
160
0
                        HINDEX_FOR_EACH_WITH_HASH_SAFE_SHORT,                 \
161
0
                        5, __VA_ARGS__)
162
163
164
/* Returns the head node in 'hindex' with the given 'hash', or a null pointer
165
 * if no nodes have that hash value. */
166
static inline struct hindex_node *
167
hindex_node_with_hash(const struct hindex *hindex, size_t hash)
168
0
{
169
0
    struct hindex_node *node = hindex->buckets[hash & hindex->mask];
170
171
0
    while (node && node->hash != hash) {
172
0
        node = node->d;
173
0
    }
174
0
    return node;
175
0
}
Unexecuted instantiation: odp-execute.c:hindex_node_with_hash
Unexecuted instantiation: conntrack.c:hindex_node_with_hash
Unexecuted instantiation: dpif-netdev.c:hindex_node_with_hash
Unexecuted instantiation: hindex.c:hindex_node_with_hash
Unexecuted instantiation: conntrack-icmp.c:hindex_node_with_hash
Unexecuted instantiation: conntrack-tcp.c:hindex_node_with_hash
Unexecuted instantiation: conntrack-tp.c:hindex_node_with_hash
Unexecuted instantiation: conntrack-other.c:hindex_node_with_hash
176
177
/* Iteration. */
178
179
/* Iterates through every node in HINDEX. */
180
#define HINDEX_FOR_EACH(NODE, MEMBER, HINDEX)                                 \
181
    for (INIT_MULTIVAR(NODE, MEMBER, hindex_first(HINDEX),                    \
182
                       struct hindex_node);                                   \
183
         CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL);            \
184
         UPDATE_MULTIVAR(NODE, hindex_next(HINDEX, ITER_VAR(NODE))))
185
186
/* Safe when NODE may be freed (not needed when NODE may be removed from the
187
 * hash index but its members remain accessible and intact). */
188
#define HINDEX_FOR_EACH_SAFE_LONG(NODE, NEXT, MEMBER, HINDEX)                 \
189
    for (INIT_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER, hindex_first(HINDEX),    \
190
                                 struct hindex_node);                         \
191
         CONDITION_MULTIVAR_SAFE_LONG(NODE, NEXT, MEMBER,                     \
192
                                      ITER_VAR(NODE) != NULL,                 \
193
                        ITER_VAR(NEXT) = hindex_next(HINDEX, ITER_VAR(NODE)), \
194
                                      ITER_VAR(NEXT) != NULL);                \
195
         UPDATE_MULTIVAR_SAFE_LONG(NODE, NEXT))
196
197
/* Short version of HINDEX_FOR_EACH_SAFE. */
198
#define HINDEX_FOR_EACH_SAFE_SHORT(NODE, MEMBER, HINDEX)                      \
199
    for (INIT_MULTIVAR_SAFE_SHORT(NODE, MEMBER, hindex_first(HINDEX),         \
200
                                  struct hindex_node);                        \
201
         CONDITION_MULTIVAR_SAFE_SHORT(NODE, MEMBER,                          \
202
                                       ITER_VAR(NODE) != NULL,                \
203
              ITER_NEXT_VAR(NODE) = hindex_next(HINDEX, ITER_VAR(NODE)));     \
204
         UPDATE_MULTIVAR_SAFE_SHORT(NODE))
205
206
#define HINDEX_FOR_EACH_SAFE(...)                                             \
207
    OVERLOAD_SAFE_MACRO(HINDEX_FOR_EACH_SAFE_LONG,                            \
208
                        HINDEX_FOR_EACH_SAFE_SHORT,                           \
209
                        4, __VA_ARGS__)
210
211
struct hindex_node *hindex_first(const struct hindex *);
212
struct hindex_node *hindex_next(const struct hindex *,
213
                                const struct hindex_node *);
214
215
/* Returns true if 'hindex' currently contains no nodes, false otherwise. */
216
static inline bool
217
hindex_is_empty(const struct hindex *hindex)
218
0
{
219
0
    return hindex->n_unique == 0;
220
0
}
Unexecuted instantiation: odp-execute.c:hindex_is_empty
Unexecuted instantiation: conntrack.c:hindex_is_empty
Unexecuted instantiation: dpif-netdev.c:hindex_is_empty
Unexecuted instantiation: hindex.c:hindex_is_empty
Unexecuted instantiation: conntrack-icmp.c:hindex_is_empty
Unexecuted instantiation: conntrack-tcp.c:hindex_is_empty
Unexecuted instantiation: conntrack-tp.c:hindex_is_empty
Unexecuted instantiation: conntrack-other.c:hindex_is_empty
221
222
#endif /* hindex.h */