]> git.proxmox.com Git - mirror_ovs.git/blame - include/openvswitch/hmap.h
conntrack: Force commit.
[mirror_ovs.git] / include / openvswitch / hmap.h
CommitLineData
064af421 1/*
bc8d7dfa 2 * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016 Nicira, Inc.
064af421 3 *
a14bc59f
BP
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:
064af421 7 *
a14bc59f
BP
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.
064af421
BP
15 */
16
17#ifndef HMAP_H
18#define HMAP_H 1
19
20#include <stdbool.h>
21#include <stdlib.h>
ee89ea7b 22#include "openvswitch/util.h"
064af421 23
0b64afd6
BP
24#ifdef __cplusplus
25extern "C" {
26#endif
27
064af421
BP
28/* A hash map node, to be embedded inside the data structure being mapped. */
29struct hmap_node {
30 size_t hash; /* Hash value. */
31 struct hmap_node *next; /* Next in linked list. */
32};
33
34/* Returns the hash value embedded in 'node'. */
35static inline size_t hmap_node_hash(const struct hmap_node *node)
36{
37 return node->hash;
38}
39
1e68c073 40#define HMAP_NODE_NULL ((struct hmap_node *) 1)
6c2e425e 41#define HMAP_NODE_NULL_INITIALIZER { 0, HMAP_NODE_NULL }
1e68c073
BP
42
43/* Returns true if 'node' has been set to null by hmap_node_nullify() and has
44 * not been un-nullified by being inserted into an hmap. */
45static inline bool
46hmap_node_is_null(const struct hmap_node *node)
47{
48 return node->next == HMAP_NODE_NULL;
49}
50
51/* Marks 'node' with a distinctive value that can be tested with
52 * hmap_node_is_null(). */
53static inline void
54hmap_node_nullify(struct hmap_node *node)
55{
56 node->next = HMAP_NODE_NULL;
57}
58
064af421
BP
59/* A hash map. */
60struct hmap {
baa8f41b 61 struct hmap_node **buckets; /* Must point to 'one' iff 'mask' == 0. */
064af421
BP
62 struct hmap_node *one;
63 size_t mask;
64 size_t n;
65};
66
67/* Initializer for an empty hash map. */
e37726e4
BP
68#define HMAP_INITIALIZER(HMAP) \
69 { (struct hmap_node **const) &(HMAP)->one, NULL, 0, 0 }
064af421 70
64982ba2
BP
71/* Initializer for an immutable struct hmap 'HMAP' that contains 'N' nodes
72 * linked together starting at 'NODE'. The hmap only has a single chain of
73 * hmap_nodes, so 'N' should be small. */
74#define HMAP_CONST(HMAP, N, NODE) { \
75 CONST_CAST(struct hmap_node **, &(HMAP)->one), NODE, 0, N }
aaf881c6 76
064af421
BP
77/* Initialization. */
78void hmap_init(struct hmap *);
79void hmap_destroy(struct hmap *);
f3099647 80void hmap_clear(struct hmap *);
064af421 81void hmap_swap(struct hmap *a, struct hmap *b);
a4af0040 82void hmap_moved(struct hmap *hmap);
064af421
BP
83static inline size_t hmap_count(const struct hmap *);
84static inline bool hmap_is_empty(const struct hmap *);
85
86/* Adjusting capacity. */
0c5e05bf 87void hmap_expand_at(struct hmap *, const char *where);
8f3676cf 88#define hmap_expand(HMAP) hmap_expand_at(HMAP, OVS_SOURCE_LOCATOR)
0c5e05bf
BP
89
90void hmap_shrink_at(struct hmap *, const char *where);
8f3676cf 91#define hmap_shrink(HMAP) hmap_shrink_at(HMAP, OVS_SOURCE_LOCATOR)
0c5e05bf
BP
92
93void hmap_reserve_at(struct hmap *, size_t capacity, const char *where);
94#define hmap_reserve(HMAP, CAPACITY) \
8f3676cf 95 hmap_reserve_at(HMAP, CAPACITY, OVS_SOURCE_LOCATOR)
064af421
BP
96
97/* Insertion and deletion. */
0c5e05bf
BP
98static inline void hmap_insert_at(struct hmap *, struct hmap_node *,
99 size_t hash, const char *where);
100#define hmap_insert(HMAP, NODE, HASH) \
8f3676cf 101 hmap_insert_at(HMAP, NODE, HASH, OVS_SOURCE_LOCATOR)
0c5e05bf 102
064af421
BP
103static inline void hmap_insert_fast(struct hmap *,
104 struct hmap_node *, size_t hash);
064af421 105static inline void hmap_remove(struct hmap *, struct hmap_node *);
064af421 106
63e60b86 107void hmap_node_moved(struct hmap *, struct hmap_node *, struct hmap_node *);
064af421 108static inline void hmap_replace(struct hmap *, const struct hmap_node *old,
43d1478b 109 struct hmap_node *new_node);
064af421 110
f2f7be86
BP
111struct hmap_node *hmap_random_node(const struct hmap *);
112
3adb8bf0
BP
113/* Search.
114 *
115 * HMAP_FOR_EACH_WITH_HASH iterates NODE over all of the nodes in HMAP that
116 * have hash value equal to HASH. HMAP_FOR_EACH_IN_BUCKET iterates NODE over
4e8e4213
BP
117 * all of the nodes in HMAP that would fall in the same bucket as HASH. MEMBER
118 * must be the name of the 'struct hmap_node' member within NODE.
3adb8bf0
BP
119 *
120 * These macros may be used interchangeably to search for a particular value in
121 * an hmap, see, e.g. shash_find() for an example. Usually, using
122 * HMAP_FOR_EACH_WITH_HASH provides an optimization, because comparing a hash
123 * value is usually cheaper than comparing an entire hash map key. But for
124 * simple hash map keys, it makes sense to use HMAP_FOR_EACH_IN_BUCKET because
125 * it avoids doing two comparisons when a single simple comparison suffices.
126 *
127 * The loop should not change NODE to point to a different node or insert or
128 * delete nodes in HMAP (unless it "break"s out of the loop to terminate
129 * iteration).
130 *
131 * HASH is only evaluated once.
48627758 132 *
f0b12cd7
RB
133 * When the loop terminates normally, meaning the iteration has completed
134 * without using 'break', NODE will be NULL. This is true for all of the
135 * HMAP_FOR_EACH_*() macros.
3adb8bf0 136 */
4e8e4213 137#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP) \
f17e8ad6 138 for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \
f0b12cd7 139 (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \
772ec52b
BP
140 ASSIGN_CONTAINER(NODE, hmap_next_with_hash(&(NODE)->MEMBER), \
141 MEMBER))
4e8e4213 142#define HMAP_FOR_EACH_IN_BUCKET(NODE, MEMBER, HASH, HMAP) \
f17e8ad6 143 for (INIT_CONTAINER(NODE, hmap_first_in_bucket(HMAP, HASH), MEMBER); \
f0b12cd7 144 (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \
772ec52b 145 ASSIGN_CONTAINER(NODE, hmap_next_in_bucket(&(NODE)->MEMBER), MEMBER))
064af421
BP
146
147static inline struct hmap_node *hmap_first_with_hash(const struct hmap *,
148 size_t hash);
149static inline struct hmap_node *hmap_next_with_hash(const struct hmap_node *);
3adb8bf0
BP
150static inline struct hmap_node *hmap_first_in_bucket(const struct hmap *,
151 size_t hash);
152static inline struct hmap_node *hmap_next_in_bucket(const struct hmap_node *);
064af421 153
e39e5b9d
BP
154bool hmap_contains(const struct hmap *, const struct hmap_node *);
155
bc8d7dfa
BP
156/* Iteration.
157 *
158 * The *_INIT variants of these macros additionally evaluate the expressions
159 * supplied following the HMAP argument once during the loop initialization.
160 * This makes it possible for data structures that wrap around hmaps to insert
161 * additional initialization into their iteration macros without having to
162 * completely rewrite them. In particular, it can be a good idea to insert
163 * BUILD_ASSERT_TYPE checks for map and node types that wrap hmap, since
164 * otherwise it is possible for clients to accidentally confuse two derived
165 * data structures that happen to use the same member names for struct hmap and
166 * struct hmap_node. */
633d7b90
BP
167
168/* Iterates through every node in HMAP. */
bc8d7dfa
BP
169#define HMAP_FOR_EACH(NODE, MEMBER, HMAP) \
170 HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, (void) 0)
171#define HMAP_FOR_EACH_INIT(NODE, MEMBER, HMAP, ...) \
172 for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__; \
f0b12cd7 173 (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \
772ec52b 174 ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
4e8e4213 175
633d7b90
BP
176/* Safe when NODE may be freed (not needed when NODE may be removed from the
177 * hash map but its members remain accessible and intact). */
bc8d7dfa
BP
178#define HMAP_FOR_EACH_SAFE(NODE, NEXT, MEMBER, HMAP) \
179 HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, (void) 0)
180#define HMAP_FOR_EACH_SAFE_INIT(NODE, NEXT, MEMBER, HMAP, ...) \
181 for (INIT_CONTAINER(NODE, hmap_first(HMAP), MEMBER), __VA_ARGS__; \
f0b12cd7 182 ((NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL) \
f17e8ad6 183 ? INIT_CONTAINER(NEXT, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), 1 \
4e8e4213 184 : 0); \
064af421
BP
185 (NODE) = (NEXT))
186
633d7b90 187/* Continues an iteration from just after NODE. */
bc8d7dfa
BP
188#define HMAP_FOR_EACH_CONTINUE(NODE, MEMBER, HMAP) \
189 HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, (void) 0)
190#define HMAP_FOR_EACH_CONTINUE_INIT(NODE, MEMBER, HMAP, ...) \
191 for (ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER), \
192 __VA_ARGS__; \
f0b12cd7 193 (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL); \
772ec52b 194 ASSIGN_CONTAINER(NODE, hmap_next(HMAP, &(NODE)->MEMBER), MEMBER))
633d7b90 195
4ec3d7c7
DDP
196static inline struct hmap_node *
197hmap_pop_helper__(struct hmap *hmap, size_t *bucket) {
198
199 for (; *bucket <= hmap->mask; (*bucket)++) {
200 struct hmap_node *node = hmap->buckets[*bucket];
201
202 if (node) {
203 hmap_remove(hmap, node);
204 return node;
205 }
206 }
207
208 return NULL;
209}
210
211#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP) \
212 for (size_t bucket__ = 0; \
213 INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \
214 (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) || (NODE = NULL);)
215
064af421
BP
216static inline struct hmap_node *hmap_first(const struct hmap *);
217static inline struct hmap_node *hmap_next(const struct hmap *,
218 const struct hmap_node *);
219
bfbcebc2
DDP
220struct hmap_position {
221 unsigned int bucket;
222 unsigned int offset;
223};
224
ee114c23 225struct hmap_node *hmap_at_position(const struct hmap *,
bfbcebc2 226 struct hmap_position *);
ee114c23 227
064af421
BP
228/* Returns the number of nodes currently in 'hmap'. */
229static inline size_t
230hmap_count(const struct hmap *hmap)
231{
232 return hmap->n;
233}
234
72865317
BP
235/* Returns the maximum number of nodes that 'hmap' may hold before it should be
236 * rehashed. */
237static inline size_t
238hmap_capacity(const struct hmap *hmap)
239{
240 return hmap->mask * 2 + 1;
241}
242
064af421 243/* Returns true if 'hmap' currently contains no nodes,
7614e5d0
JR
244 * false otherwise.
245 * Note: While hmap in general is not thread-safe without additional locking,
246 * hmap_is_empty() is. */
064af421
BP
247static inline bool
248hmap_is_empty(const struct hmap *hmap)
249{
250 return hmap->n == 0;
251}
252
253/* Inserts 'node', with the given 'hash', into 'hmap'. 'hmap' is never
254 * expanded automatically. */
255static inline void
256hmap_insert_fast(struct hmap *hmap, struct hmap_node *node, size_t hash)
257{
258 struct hmap_node **bucket = &hmap->buckets[hash & hmap->mask];
259 node->hash = hash;
260 node->next = *bucket;
261 *bucket = node;
262 hmap->n++;
263}
264
265/* Inserts 'node', with the given 'hash', into 'hmap', and expands 'hmap' if
0c5e05bf
BP
266 * necessary to optimize search performance.
267 *
268 * ('where' is used in debug logging. Commonly one would use hmap_insert() to
269 * automatically provide the caller's source file and line number for
270 * 'where'.) */
064af421 271static inline void
0c5e05bf
BP
272hmap_insert_at(struct hmap *hmap, struct hmap_node *node, size_t hash,
273 const char *where)
064af421
BP
274{
275 hmap_insert_fast(hmap, node, hash);
276 if (hmap->n / 2 > hmap->mask) {
0c5e05bf 277 hmap_expand_at(hmap, where);
064af421
BP
278 }
279}
280
281/* Removes 'node' from 'hmap'. Does not shrink the hash table; call
282 * hmap_shrink() directly if desired. */
283static inline void
284hmap_remove(struct hmap *hmap, struct hmap_node *node)
285{
286 struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask];
287 while (*bucket != node) {
288 bucket = &(*bucket)->next;
289 }
290 *bucket = node->next;
291 hmap->n--;
292}
293
0b64afd6
BP
294/* Puts 'new_node' in the position in 'hmap' currently occupied by 'old_node'.
295 * The 'new_node' must hash to the same value as 'old_node'. The client is
296 * responsible for ensuring that the replacement does not violate any
297 * client-imposed invariants (e.g. uniqueness of keys within a map).
064af421 298 *
0b64afd6
BP
299 * Afterward, 'old_node' is not part of 'hmap', and the client is responsible
300 * for freeing it (if this is desirable). */
064af421
BP
301static inline void
302hmap_replace(struct hmap *hmap,
0b64afd6 303 const struct hmap_node *old_node, struct hmap_node *new_node)
064af421 304{
0b64afd6
BP
305 struct hmap_node **bucket = &hmap->buckets[old_node->hash & hmap->mask];
306 while (*bucket != old_node) {
064af421
BP
307 bucket = &(*bucket)->next;
308 }
0b64afd6
BP
309 *bucket = new_node;
310 new_node->hash = old_node->hash;
a4af0040 311 new_node->next = old_node->next;
064af421
BP
312}
313
314static inline struct hmap_node *
315hmap_next_with_hash__(const struct hmap_node *node, size_t hash)
316{
317 while (node != NULL && node->hash != hash) {
318 node = node->next;
319 }
ebc56baa 320 return CONST_CAST(struct hmap_node *, node);
064af421
BP
321}
322
323/* Returns the first node in 'hmap' with the given 'hash', or a null pointer if
324 * no nodes have that hash value. */
325static inline struct hmap_node *
326hmap_first_with_hash(const struct hmap *hmap, size_t hash)
327{
328 return hmap_next_with_hash__(hmap->buckets[hash & hmap->mask], hash);
329}
330
3adb8bf0
BP
331/* Returns the first node in 'hmap' in the bucket in which the given 'hash'
332 * would land, or a null pointer if that bucket is empty. */
333static inline struct hmap_node *
334hmap_first_in_bucket(const struct hmap *hmap, size_t hash)
335{
336 return hmap->buckets[hash & hmap->mask];
337}
338
339/* Returns the next node in the same bucket as 'node', or a null pointer if
340 * there are no more nodes in that bucket.
341 *
342 * If the hash map has been reallocated since 'node' was visited, some nodes
343 * may be skipped; if new nodes with the same hash value have been added, they
344 * will be skipped. (Removing 'node' from the hash map does not prevent
345 * calling this function, since node->next is preserved, although freeing
346 * 'node' of course does.) */
347static inline struct hmap_node *
348hmap_next_in_bucket(const struct hmap_node *node)
349{
350 return node->next;
351}
352
064af421
BP
353/* Returns the next node in the same hash map as 'node' with the same hash
354 * value, or a null pointer if no more nodes have that hash value.
355 *
356 * If the hash map has been reallocated since 'node' was visited, some nodes
357 * may be skipped; if new nodes with the same hash value have been added, they
358 * will be skipped. (Removing 'node' from the hash map does not prevent
359 * calling this function, since node->next is preserved, although freeing
360 * 'node' of course does.) */
361static inline struct hmap_node *
362hmap_next_with_hash(const struct hmap_node *node)
363{
364 return hmap_next_with_hash__(node->next, node->hash);
365}
366
367static inline struct hmap_node *
368hmap_next__(const struct hmap *hmap, size_t start)
369{
370 size_t i;
371 for (i = start; i <= hmap->mask; i++) {
372 struct hmap_node *node = hmap->buckets[i];
373 if (node) {
374 return node;
375 }
376 }
377 return NULL;
378}
379
380/* Returns the first node in 'hmap', in arbitrary order, or a null pointer if
381 * 'hmap' is empty. */
382static inline struct hmap_node *
383hmap_first(const struct hmap *hmap)
384{
385 return hmap_next__(hmap, 0);
386}
387
388/* Returns the next node in 'hmap' following 'node', in arbitrary order, or a
389 * null pointer if 'node' is the last node in 'hmap'.
390 *
391 * If the hash map has been reallocated since 'node' was visited, some nodes
392 * may be skipped or visited twice. (Removing 'node' from the hash map does
393 * not prevent calling this function, since node->next is preserved, although
394 * freeing 'node' of course does.) */
395static inline struct hmap_node *
396hmap_next(const struct hmap *hmap, const struct hmap_node *node)
397{
398 return (node->next
399 ? node->next
400 : hmap_next__(hmap, (node->hash & hmap->mask) + 1));
401}
402
0b64afd6
BP
403#ifdef __cplusplus
404}
405#endif
406
064af421 407#endif /* hmap.h */