Line data Source code
1 0 : /* 2 : * Copyright (c) 2022 Meta 3 : * 4 : * SPDX-License-Identifier: Apache-2.0 5 : */ 6 : 7 : #ifndef ZEPHYR_INCLUDE_SYS_HASHMAP_API_H_ 8 : #define ZEPHYR_INCLUDE_SYS_HASHMAP_API_H_ 9 : 10 : #include <stdbool.h> 11 : #include <stddef.h> 12 : #include <stdint.h> 13 : 14 : #include <zephyr/sys/hash_function.h> 15 : #include <zephyr/sys/util.h> 16 : 17 : #ifdef __cplusplus 18 : extern "C" { 19 : #endif 20 : 21 : /** 22 : * @file 23 : * @defgroup hashmap_apis Hashmap 24 : * @ingroup datastructure_apis 25 : * 26 : * @brief Hashmap (Hash Table) API 27 : * 28 : * Hashmaps (a.k.a Hash Tables) sacrifice space for speed. All operations 29 : * on a Hashmap (insert, delete, search) are O(1) complexity (on average). 30 : * 31 : * @defgroup hashmap_implementations Hashmap Implementations 32 : * @ingroup hashmap_apis 33 : * 34 : * @addtogroup hashmap_apis 35 : * @{ 36 : */ 37 : 38 : /** 39 : * @brief Generic Hashmap iterator interface 40 : * 41 : * @note @a next should not be used without first checking 42 : * @ref sys_hashmap_iterator_has_next 43 : */ 44 1 : struct sys_hashmap_iterator { 45 : /** Pointer to the associated Hashmap */ 46 1 : const struct sys_hashmap *map; 47 : /** Modify the iterator in-place to point to the next Hashmap entry */ 48 1 : void (*next)(struct sys_hashmap_iterator *it); 49 : /** Implementation-specific iterator state */ 50 1 : void *state; 51 : /** Key associated with the current entry */ 52 1 : uint64_t key; 53 : /** Value associated with the current entry */ 54 1 : uint64_t value; 55 : /** Number of entries in the map */ 56 1 : const size_t size; 57 : /** Number of entries already iterated */ 58 1 : size_t pos; 59 : }; 60 : 61 : /** 62 : * @brief Check if a Hashmap iterator has a next entry 63 : * 64 : * @param it Hashmap iterator 65 : * @return true if there is a next entry 66 : * @return false if there is no next entry 67 : */ 68 1 : static inline bool sys_hashmap_iterator_has_next(const struct sys_hashmap_iterator *it) 69 : { 70 : return it->pos < it->size; 71 : } 72 : 73 : /** 74 : * @brief Allocator interface for @ref sys_hashmap 75 : * 76 : * The Hashmap allocator can be any allocator that behaves similarly to `realloc()` with the 77 : * additional specification that the allocator behaves like `free()` when @p new_size is zero. 78 : * 79 : * @param ptr Previously allocated memory region or `NULL` to make a new vallocation. 80 : * @param new_size the new size of the allocation, in bytes. 81 : * 82 : * @see <a href="https://en.cppreference.com/w/c/memory/realloc">realloc</a> 83 : */ 84 1 : typedef void *(*sys_hashmap_allocator_t)(void *ptr, size_t new_size); 85 : 86 : /** 87 : * @brief In-place iterator constructor for @ref sys_hashmap 88 : * 89 : * Construct an iterator, @p it, for @p map. 90 : * 91 : * @param map Hashmap to iterate over. 92 : * @param it Iterator to initialize. 93 : */ 94 1 : typedef void (*sys_hashmap_iterator_t)(const struct sys_hashmap *map, 95 : struct sys_hashmap_iterator *it); 96 : 97 : /** 98 : * @brief Callback interface for @ref sys_hashmap 99 : * 100 : * This callback is used by some Hashmap methods. 101 : * 102 : * @param key Key corresponding to @p value 103 : * @param value Value corresponding to @p key 104 : * @param cookie User-specified variable 105 : */ 106 1 : typedef void (*sys_hashmap_callback_t)(uint64_t key, uint64_t value, void *cookie); 107 : 108 : /** 109 : * @brief Clear all entries contained in a @ref sys_hashmap 110 : * 111 : * @note If the values in a particular Hashmap are 112 : * 113 : * @param map Hashmap to clear 114 : * @param cb Callback to call for each entry 115 : * @param cookie User-specified variable 116 : */ 117 1 : typedef void (*sys_hashmap_clear_t)(struct sys_hashmap *map, sys_hashmap_callback_t cb, 118 : void *cookie); 119 : 120 : /** 121 : * @brief Insert a new entry into a @ref sys_hashmap 122 : * 123 : * Insert a new @p key - @p value pair into @p map. 124 : * 125 : * @param map Hashmap to insert into 126 : * @param key Key to associate with @p value 127 : * @param value Value to associate with @p key 128 : * @param old_value Location to store the value previously associated with @p key or `NULL` 129 : * @retval 0 if @p value was inserted for an existing key, in which case @p old_value will contain 130 : * the previous value 131 : * @retval 1 if a new entry was inserted for the @p key - @p value pair 132 : * @retval -ENOMEM if memory allocation failed 133 : */ 134 1 : typedef int (*sys_hashmap_insert_t)(struct sys_hashmap *map, uint64_t key, uint64_t value, 135 : uint64_t *old_value); 136 : 137 : /** 138 : * @brief Remove an entry from a @ref sys_hashmap 139 : * 140 : * Erase the entry associated with key @p key, if one exists. 141 : * 142 : * @param map Hashmap to remove from 143 : * @param key Key to remove from @p map 144 : * @param value Location to store a potential value associated with @p key or `NULL` 145 : * 146 : * @retval true if @p map was modified as a result of this operation. 147 : * @retval false if @p map does not contain a value associated with @p key. 148 : */ 149 1 : typedef bool (*sys_hashmap_remove_t)(struct sys_hashmap *map, uint64_t key, uint64_t *value); 150 : 151 : /** 152 : * @brief Get a value from a @ref sys_hashmap 153 : * 154 : * Look-up the @ref uint64_t associated with @p key, if one exists. 155 : * 156 : * @param map Hashmap to search through 157 : * @param key Key with which to search @p map 158 : * @param value Location to store a potential value associated with @p key or `NULL` 159 : * 160 : * @retval true if @p map contains a value associated with @p key. 161 : * @retval false if @p map does not contain a value associated with @p key. 162 : */ 163 1 : typedef bool (*sys_hashmap_get_t)(const struct sys_hashmap *map, uint64_t key, uint64_t *value); 164 : 165 : /** 166 : * @brief Generic Hashmap API 167 : */ 168 1 : struct sys_hashmap_api { 169 : /** Iterator constructor (in-place) */ 170 1 : sys_hashmap_iterator_t iter; 171 : /** Clear the hash table, freeing all resources */ 172 1 : sys_hashmap_clear_t clear; 173 : /** Insert a key-value pair into the Hashmap */ 174 1 : sys_hashmap_insert_t insert; 175 : /** Remove a key-value pair from the Hashmap */ 176 1 : sys_hashmap_remove_t remove; 177 : /** Retrieve the value associated with a given key from the Hashmap */ 178 1 : sys_hashmap_get_t get; 179 : }; 180 : 181 : /** 182 : * @brief Generic Hashmap configuration 183 : * 184 : * When there is a known limit imposed on the number of entries in the Hashmap, 185 : * users should specify that via @a max_size. When the Hashmap should have 186 : * no artificial limitation in size (and be bounded only by the provided 187 : * allocator), users should specify `SIZE_MAX` here. 188 : * 189 : * The @a load_factor is defined as the size of the Hashmap divided by the 190 : * number of buckets. In this case, the size of the Hashmap is defined as 191 : * the number of valid entries plus the number of invalidated entries. 192 : * 193 : * The @a initial_n_buckets is defined as the number of buckets to allocate 194 : * when moving from size 0 to size 1 such that the maximum @a load_factor 195 : * property is preserved. 196 : */ 197 1 : struct sys_hashmap_config { 198 : /** Maximum number of entries */ 199 1 : size_t max_size; 200 : /** Maximum load factor expressed in hundredths */ 201 1 : uint8_t load_factor; 202 : /** Initial number of buckets to allocate */ 203 1 : uint8_t initial_n_buckets; 204 : }; 205 : 206 : /** 207 : * @brief Initializer for @p sys_hashmap_config 208 : * 209 : * This macro helps to initialize a structure of type @p sys_hashmap_config. 210 : * 211 : * @param _max_size Maximum number of entries 212 : * @param _load_factor Maximum load factor of expressed in hundredths 213 : */ 214 1 : #define SYS_HASHMAP_CONFIG(_max_size, _load_factor) \ 215 : { \ 216 : .max_size = (size_t)_max_size, .load_factor = (uint8_t)_load_factor, \ 217 : .initial_n_buckets = NHPOT(DIV_ROUND_UP(100, _load_factor)), \ 218 : } 219 : 220 : /** 221 : * @brief Generic Hashmap data 222 : * 223 : * @note When @a size is zero, @a buckets should be `NULL`. 224 : */ 225 1 : struct sys_hashmap_data { 226 : /** Pointer for implementation-specific Hashmap storage */ 227 1 : void *buckets; 228 : /** The number of buckets currently allocated */ 229 1 : size_t n_buckets; 230 : /** The number of entries currently in the Hashmap */ 231 1 : size_t size; 232 : }; 233 : 234 : /** @} */ 235 : 236 : #ifdef __cplusplus 237 : } 238 : #endif 239 : 240 : #endif /* ZEPHYR_INCLUDE_SYS_HASHMAP_API_H_ */