/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford * Junior University * * We are making the OpenFlow specification and associated documentation * (Software) available for public use and benefit with the expectation * that others will use, modify and enhance the Software and contribute * those enhancements back to the community. However, since we would * like to make the Software available for broadest use, with as few * restrictions as possible permission is hereby granted, free of * charge, to any person obtaining a copy of this Software to deal in * the Software under the copyrights without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * The name and trademarks of copyright holder(s) may NOT be used in * advertising or publicity pertaining to the Software or any * derivatives without specific, written prior permission. */ #ifndef HMAP_H #define HMAP_H 1 #include #include #include "util.h" /* A hash map node, to be embedded inside the data structure being mapped. */ struct hmap_node { size_t hash; /* Hash value. */ struct hmap_node *next; /* Next in linked list. */ }; /* Returns the hash value embedded in 'node'. */ static inline size_t hmap_node_hash(const struct hmap_node *node) { return node->hash; } /* A hash map. */ struct hmap { struct hmap_node **buckets; struct hmap_node *one; size_t mask; size_t n; }; /* Initializer for an empty hash map. */ #define HMAP_INITIALIZER(HMAP) { &(HMAP)->one, NULL, 0, 0 } /* Initialization. */ void hmap_init(struct hmap *); void hmap_destroy(struct hmap *); void hmap_swap(struct hmap *a, struct hmap *b); static inline size_t hmap_count(const struct hmap *); static inline bool hmap_is_empty(const struct hmap *); /* Adjusting capacity. */ void hmap_expand(struct hmap *); void hmap_shrink(struct hmap *); void hmap_reserve(struct hmap *, size_t capacity); /* Insertion and deletion. */ static inline void hmap_insert_fast(struct hmap *, struct hmap_node *, size_t hash); static inline void hmap_insert(struct hmap *, struct hmap_node *, size_t hash); static inline void hmap_remove(struct hmap *, struct hmap_node *); /* Search. */ #define HMAP_FOR_EACH_WITH_HASH(NODE, STRUCT, MEMBER, HASH, HMAP) \ for ((NODE) = CONTAINER_OF(hmap_first_with_hash(HMAP, HASH), \ STRUCT, MEMBER); \ &(NODE)->MEMBER != NULL; \ (NODE) = CONTAINER_OF(hmap_next_with_hash(&(NODE)->MEMBER), \ STRUCT, MEMBER)) static inline struct hmap_node *hmap_first_with_hash(const struct hmap *, size_t hash); static inline struct hmap_node *hmap_next_with_hash(const struct hmap_node *); /* Iteration. * * The _SAFE version is needed when NODE may be freed. It is not needed when * NODE may be removed from the hash map but its members remain accessible and * intact. */ #define HMAP_FOR_EACH(NODE, STRUCT, MEMBER, HMAP) \ for ((NODE) = CONTAINER_OF(hmap_first(HMAP), STRUCT, MEMBER); \ &(NODE)->MEMBER != NULL; \ (NODE) = CONTAINER_OF(hmap_next(HMAP, &(NODE)->MEMBER), \ STRUCT, MEMBER)) #define HMAP_FOR_EACH_SAFE(NODE, NEXT, STRUCT, MEMBER, HMAP) \ for ((NODE) = CONTAINER_OF(hmap_first(HMAP), STRUCT, MEMBER); \ (&(NODE)->MEMBER != NULL \ ? (NEXT) = CONTAINER_OF(hmap_next(HMAP, &(NODE)->MEMBER), \ STRUCT, MEMBER), 1 \ : 0); \ (NODE) = (NEXT)) static inline struct hmap_node *hmap_first(const struct hmap *); static inline struct hmap_node *hmap_next(const struct hmap *, const struct hmap_node *); /* Returns the number of nodes currently in 'hmap'. */ static inline size_t hmap_count(const struct hmap *hmap) { return hmap->n; } /* Returns true if 'hmap' currently contains no nodes, * false otherwise. */ static inline bool hmap_is_empty(const struct hmap *hmap) { return hmap->n == 0; } /* Inserts 'node', with the given 'hash', into 'hmap'. 'hmap' is never * expanded automatically. */ static inline void hmap_insert_fast(struct hmap *hmap, struct hmap_node *node, size_t hash) { struct hmap_node **bucket = &hmap->buckets[hash & hmap->mask]; node->hash = hash; node->next = *bucket; *bucket = node; hmap->n++; } /* Inserts 'node', with the given 'hash', into 'hmap', and expands 'hmap' if * necessary to optimize search performance. */ static inline void hmap_insert(struct hmap *hmap, struct hmap_node *node, size_t hash) { hmap_insert_fast(hmap, node, hash); if (hmap->n / 2 > hmap->mask) { hmap_expand(hmap); } } /* Removes 'node' from 'hmap'. Does not shrink the hash table; call * hmap_shrink() directly if desired. */ static inline void hmap_remove(struct hmap *hmap, struct hmap_node *node) { struct hmap_node **bucket = &hmap->buckets[node->hash & hmap->mask]; while (*bucket != node) { bucket = &(*bucket)->next; } *bucket = node->next; hmap->n--; } static inline struct hmap_node * hmap_next_with_hash__(const struct hmap_node *node, size_t hash) { while (node != NULL && node->hash != hash) { node = node->next; } return (struct hmap_node *) node; } /* Returns the first node in 'hmap' with the given 'hash', or a null pointer if * no nodes have that hash value. */ static inline struct hmap_node * hmap_first_with_hash(const struct hmap *hmap, size_t hash) { return hmap_next_with_hash__(hmap->buckets[hash & hmap->mask], hash); } /* Returns the next node in the same hash map as 'node' with the same hash * value, or a null pointer if no more nodes have that hash value. * * If the hash map has been reallocated since 'node' was visited, some nodes * may be skipped; if new nodes with the same hash value have been added, they * will be skipped. (Removing 'node' from the hash map does not prevent * calling this function, since node->next is preserved, although freeing * 'node' of course does.) */ static inline struct hmap_node * hmap_next_with_hash(const struct hmap_node *node) { return hmap_next_with_hash__(node->next, node->hash); } static inline struct hmap_node * hmap_next__(const struct hmap *hmap, size_t start) { size_t i; for (i = start; i <= hmap->mask; i++) { struct hmap_node *node = hmap->buckets[i]; if (node) { return node; } } return NULL; } /* Returns the first node in 'hmap', in arbitrary order, or a null pointer if * 'hmap' is empty. */ static inline struct hmap_node * hmap_first(const struct hmap *hmap) { return hmap_next__(hmap, 0); } /* Returns the next node in 'hmap' following 'node', in arbitrary order, or a * null pointer if 'node' is the last node in 'hmap'. * * If the hash map has been reallocated since 'node' was visited, some nodes * may be skipped or visited twice. (Removing 'node' from the hash map does * not prevent calling this function, since node->next is preserved, although * freeing 'node' of course does.) */ static inline struct hmap_node * hmap_next(const struct hmap *hmap, const struct hmap_node *node) { return (node->next ? node->next : hmap_next__(hmap, (node->hash & hmap->mask) + 1)); } #endif /* hmap.h */