LCOV - code coverage report
Current view: top level - zephyr/sys - hash_map.h Coverage Total Hit
Test: new.info Lines: 92.0 % 25 23
Test Date: 2025-09-05 20:47:19

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2022 Meta
       3              :  *
       4              :  * SPDX-License-Identifier: Apache-2.0
       5              :  */
       6              : 
       7              : /**
       8              :  * @file
       9              :  * @addtogroup hashmap_apis
      10              :  * @{
      11              :  */
      12              : 
      13              : #ifndef ZEPHYR_INCLUDE_SYS_HASH_MAP_H_
      14              : #define ZEPHYR_INCLUDE_SYS_HASH_MAP_H_
      15              : 
      16              : #include <stdbool.h>
      17              : #include <stddef.h>
      18              : #include <stdint.h>
      19              : #include <stdlib.h>
      20              : 
      21              : #include <zephyr/kernel.h>
      22              : #include <zephyr/sys/hash_map_api.h>
      23              : #include <zephyr/sys/hash_map_cxx.h>
      24              : #include <zephyr/sys/hash_map_oa_lp.h>
      25              : #include <zephyr/sys/hash_map_sc.h>
      26              : 
      27              : #ifdef __cplusplus
      28              : extern "C" {
      29              : #endif
      30              : 
      31              : /**
      32              :  * @brief Declare a Hashmap (advanced)
      33              :  *
      34              :  * Declare a Hashmap with control over advanced parameters.
      35              :  *
      36              :  * @note The allocator @p _alloc is used for allocating internal Hashmap
      37              :  * entries and does not interact with any user-provided keys or values.
      38              :  *
      39              :  * @param _name Name of the Hashmap.
      40              :  * @param _api API pointer of type @ref sys_hashmap_api.
      41              :  * @param _config_type Variant of @ref sys_hashmap_config.
      42              :  * @param _data_type Variant of @ref sys_hashmap_data.
      43              :  * @param _hash_func Hash function pointer of type @ref sys_hash_func32_t.
      44              :  * @param _alloc_func Allocator function pointer of type @ref sys_hashmap_allocator_t.
      45              :  * @param ... Variant-specific details for @p _config_type.
      46              :  */
      47              : #define SYS_HASHMAP_DEFINE_ADVANCED(_name, _api, _config_type, _data_type, _hash_func,             \
      48            1 :                                     _alloc_func, ...)                                              \
      49              :         const struct _config_type _name##_config = __VA_ARGS__;                                    \
      50              :         struct _data_type _name##_data;                                                            \
      51              :         struct sys_hashmap _name = {                                                               \
      52              :                 .api = (const struct sys_hashmap_api *)(_api),                                     \
      53              :                 .config = (const struct sys_hashmap_config *)&_name##_config,                      \
      54              :                 .data = (struct sys_hashmap_data *)&_name##_data,                                  \
      55              :                 .hash_func = (_hash_func),                                                         \
      56              :                 .alloc_func = (_alloc_func),                                                       \
      57              :         }
      58              : 
      59              : /**
      60              :  * @brief Declare a Hashmap statically (advanced)
      61              :  *
      62              :  * Declare a Hashmap statically with control over advanced parameters.
      63              :  *
      64              :  * @note The allocator @p _alloc is used for allocating internal Hashmap
      65              :  * entries and does not interact with any user-provided keys or values.
      66              :  *
      67              :  * @param _name Name of the Hashmap.
      68              :  * @param _api API pointer of type @ref sys_hashmap_api.
      69              :  * @param _config_type Variant of @ref sys_hashmap_config.
      70              :  * @param _data_type Variant of @ref sys_hashmap_data.
      71              :  * @param _hash_func Hash function pointer of type @ref sys_hash_func32_t.
      72              :  * @param _alloc_func Allocator function pointer of type @ref sys_hashmap_allocator_t.
      73              :  * @param ... Variant-specific details for @p _config_type.
      74              :  */
      75              : #define SYS_HASHMAP_DEFINE_STATIC_ADVANCED(_name, _api, _config_type, _data_type, _hash_func,      \
      76            1 :                                            _alloc_func, ...)                                       \
      77              :         static const struct _config_type _name##_config = __VA_ARGS__;                             \
      78              :         static struct _data_type _name##_data;                                                     \
      79              :         static struct sys_hashmap _name = {                                                        \
      80              :                 .api = (const struct sys_hashmap_api *)(_api),                                     \
      81              :                 .config = (const struct sys_hashmap_config *)&_name##_config,                      \
      82              :                 .data = (struct sys_hashmap_data *)&_name##_data,                                  \
      83              :                 .hash_func = (_hash_func),                                                         \
      84              :                 .alloc_func = (_alloc_func),                                                       \
      85              :         }
      86              : 
      87              : /**
      88              :  * @brief Declare a Hashmap
      89              :  *
      90              :  * Declare a Hashmap with default parameters.
      91              :  *
      92              :  * @param _name Name of the Hashmap.
      93              :  */
      94            1 : #define SYS_HASHMAP_DEFINE(_name) SYS_HASHMAP_DEFAULT_DEFINE(_name)
      95              : 
      96              : /**
      97              :  * @brief Declare a Hashmap statically
      98              :  *
      99              :  * Declare a Hashmap statically with default parameters.
     100              :  *
     101              :  * @param _name Name of the Hashmap.
     102              :  */
     103            1 : #define SYS_HASHMAP_DEFINE_STATIC(_name) SYS_HASHMAP_DEFAULT_DEFINE_STATIC(_name)
     104              : 
     105              : /*
     106              :  * A safe wrapper for realloc(), invariant of which libc provides it.
     107              :  */
     108            0 : static inline void *sys_hashmap_default_allocator(void *ptr, size_t size)
     109              : {
     110              :         if (size == 0) {
     111              :                 free(ptr);
     112              :                 return NULL;
     113              :         }
     114              : 
     115              :         return realloc(ptr, size);
     116              : }
     117              : 
     118              : /** @brief The default Hashmap allocator */
     119            1 : #define SYS_HASHMAP_DEFAULT_ALLOCATOR sys_hashmap_default_allocator
     120              : 
     121              : /** @brief The default Hashmap load factor (in hundredths) */
     122            1 : #define SYS_HASHMAP_DEFAULT_LOAD_FACTOR 75
     123              : 
     124              : /** @brief Generic Hashmap */
     125            1 : struct sys_hashmap {
     126              :         /** Hashmap API */
     127            1 :         const struct sys_hashmap_api *api;
     128              :         /** Hashmap configuration */
     129            1 :         const struct sys_hashmap_config *config;
     130              :         /** Hashmap data */
     131            1 :         struct sys_hashmap_data *data;
     132              :         /** Hash function */
     133            1 :         sys_hash_func32_t hash_func;
     134              :         /** Allocator */
     135            1 :         sys_hashmap_allocator_t alloc_func;
     136              : };
     137              : 
     138              : /**
     139              :  * @brief Iterate over all values contained in a @ref sys_hashmap
     140              :  *
     141              :  * @param map Hashmap to iterate over
     142              :  * @param cb Callback to call for each entry
     143              :  * @param cookie User-specified variable
     144              :  */
     145            1 : static inline void sys_hashmap_foreach(const struct sys_hashmap *map, sys_hashmap_callback_t cb,
     146              :                                        void *cookie)
     147              : {
     148              :         struct sys_hashmap_iterator it = {0};
     149              : 
     150              :         for (map->api->iter(map, &it); sys_hashmap_iterator_has_next(&it);) {
     151              :                 it.next(&it);
     152              :                 cb(it.key, it.value, cookie);
     153              :         }
     154              : }
     155              : 
     156              : /**
     157              :  * @brief Clear all entries contained in a @ref sys_hashmap
     158              :  *
     159              :  * @note If the values in a particular Hashmap are
     160              :  *
     161              :  * @param map Hashmap to clear
     162              :  * @param cb Callback to call for each entry
     163              :  * @param cookie User-specified variable
     164              :  */
     165            1 : static inline void sys_hashmap_clear(struct sys_hashmap *map, sys_hashmap_callback_t cb,
     166              :                                      void *cookie)
     167              : {
     168              :         map->api->clear(map, cb, cookie);
     169              : }
     170              : 
     171              : /**
     172              :  * @brief Insert a new entry into a @ref sys_hashmap
     173              :  *
     174              :  * Insert a new @p key - @p value pair into @p map.
     175              :  *
     176              :  * @param map Hashmap to insert into
     177              :  * @param key Key to associate with @p value
     178              :  * @param value Value to associate with @p key
     179              :  * @param old_value Location to store the value previously associated with @p key or `NULL`
     180              :  * @retval 0 if @p value was inserted for an existing key, in which case @p old_value will contain
     181              :  * the previous value
     182              :  * @retval 1 if a new entry was inserted for the @p key - @p value pair
     183              :  * @retval -ENOMEM if memory allocation failed
     184              :  * @retval -ENOSPC if the size limit has been reached
     185              :  */
     186            1 : static inline int sys_hashmap_insert(struct sys_hashmap *map, uint64_t key, uint64_t value,
     187              :                                      uint64_t *old_value)
     188              : {
     189              :         return map->api->insert(map, key, value, old_value);
     190              : }
     191              : 
     192              : /**
     193              :  * @brief Remove an entry from a @ref sys_hashmap
     194              :  *
     195              :  * Erase the entry associated with key @p key, if one exists.
     196              :  *
     197              :  * @param map Hashmap to remove from
     198              :  * @param key Key to remove from @p map
     199              :  * @param value Location to store a potential value associated with @p key or `NULL`
     200              :  *
     201              :  * @retval true if @p map was modified as a result of this operation.
     202              :  * @retval false if @p map does not contain a value associated with @p key.
     203              :  */
     204            1 : static inline bool sys_hashmap_remove(struct sys_hashmap *map, uint64_t key, uint64_t *value)
     205              : {
     206              :         return map->api->remove(map, key, value);
     207              : }
     208              : 
     209              : /**
     210              :  * @brief Get a value from a @ref sys_hashmap
     211              :  *
     212              :  * Look-up the @ref uint64_t associated with @p key, if one exists.
     213              :  *
     214              :  * @param map Hashmap to search through
     215              :  * @param key Key with which to search @p map
     216              :  * @param value Location to store a potential value associated with @p key or `NULL`
     217              :  *
     218              :  * @retval true if @p map contains a value associated with @p key.
     219              :  * @retval false if @p map does not contain a value associated with @p key.
     220              :  */
     221            1 : static inline bool sys_hashmap_get(const struct sys_hashmap *map, uint64_t key, uint64_t *value)
     222              : {
     223              :         return map->api->get(map, key, value);
     224              : }
     225              : 
     226              : /**
     227              :  * @brief Check if @p map contains a value associated with @p key
     228              :  *
     229              :  * @param map Hashmap to search through
     230              :  * @param key Key with which to search @p map
     231              :  *
     232              :  * @retval true if @p map contains a value associated with @p key.
     233              :  * @retval false if @p map does not contain a value associated with @p key.
     234              :  */
     235            1 : static inline bool sys_hashmap_contains_key(const struct sys_hashmap *map, uint64_t key)
     236              : {
     237              :         return sys_hashmap_get(map, key, NULL);
     238              : }
     239              : 
     240              : /**
     241              :  * @brief Query the number of entries contained within @p map
     242              :  *
     243              :  * @param map Hashmap to search through
     244              :  *
     245              :  * @return the number of entries contained within @p map.
     246              :  */
     247            1 : static inline size_t sys_hashmap_size(const struct sys_hashmap *map)
     248              : {
     249              :         return map->data->size;
     250              : }
     251              : 
     252              : /**
     253              :  * @brief Check if @p map is empty
     254              :  *
     255              :  * @param map Hashmap to query
     256              :  *
     257              :  * @retval true if @p map is empty.
     258              :  * @retval false if @p map is not empty.
     259              :  */
     260            1 : static inline bool sys_hashmap_is_empty(const struct sys_hashmap *map)
     261              : {
     262              :         return map->data->size == 0;
     263              : }
     264              : 
     265              : /**
     266              :  * @brief Query the load factor of @p map
     267              :  *
     268              :  * @note To convert the load factor to a floating-point value use
     269              :  * `sys_hash_load_factor(map) / 100.0f`.
     270              :  *
     271              :  * @param map Hashmap to query
     272              :  *
     273              :  * @return Load factor of @p map expressed in hundredths.
     274              :  */
     275            1 : static inline uint8_t sys_hashmap_load_factor(const struct sys_hashmap *map)
     276              : {
     277              :         if (map->data->n_buckets == 0) {
     278              :                 return 0;
     279              :         }
     280              : 
     281              :         return (map->data->size * 100) / map->data->n_buckets;
     282              : }
     283              : 
     284              : /**
     285              :  * @brief Query the number of buckets used in @p map
     286              :  *
     287              :  * @param map Hashmap to query
     288              :  * @return Number of buckets used in @p map
     289              :  */
     290            1 : static inline size_t sys_hashmap_num_buckets(const struct sys_hashmap *map)
     291              : {
     292              :         return map->data->n_buckets;
     293              : }
     294              : 
     295              : /**
     296              :  * @brief Decide whether the Hashmap should be resized
     297              :  *
     298              :  * This is a simple opportunistic method that implementations
     299              :  * can choose to use. It will grow and shrink the Hashmap by a factor
     300              :  * of 2 when insertion / removal would exceed / fall into the specified
     301              :  * load factor.
     302              :  *
     303              :  * @note Users should call this prior to inserting a new key-value pair and after removing a
     304              :  * key-value pair.
     305              :  *
     306              :  * @note The number of reserved entries is implementation-defined, but it is only considered
     307              :  * as part of the load factor when growing the hash table.
     308              :  *
     309              :  * @param map Hashmap to examine
     310              :  * @param grow true if an entry is to be added. false if an entry has been removed
     311              :  * @param num_reserved the number of reserved entries
     312              :  * @param[out] new_num_buckets variable Hashmap size
     313              :  * @return true if the Hashmap should be rehashed
     314              :  * @return false if the Hashmap should not be rehashed
     315              :  */
     316            1 : static inline bool sys_hashmap_should_rehash(const struct sys_hashmap *map, bool grow,
     317              :                                              size_t num_reserved, size_t *new_num_buckets)
     318              : {
     319              :         size_t size;
     320              :         bool should_grow;
     321              :         size_t n_buckets;
     322              :         bool should_shrink;
     323              :         const bool shrink = !grow;
     324              :         struct sys_hashmap_oa_lp_data *const data = (struct sys_hashmap_oa_lp_data *)map->data;
     325              :         const struct sys_hashmap_config *const config = map->config;
     326              : 
     327              :         /* All branchless calculations, so very cache-friendly */
     328              : 
     329              :         /* calculate new size */
     330              :         size = data->size;
     331              :         size += grow;
     332              :         /* maximum size imposed by the implementation */
     333              :         __ASSERT_NO_MSG(size < SIZE_MAX / 100);
     334              : 
     335              :         /* calculate new number of buckets */
     336              :         n_buckets = data->n_buckets;
     337              :         /* initial number of buckets */
     338              :         n_buckets += grow * (size == 1) * config->initial_n_buckets;
     339              :         /* grow at a rate of 2x */
     340              :         n_buckets <<= grow * (size != 1);
     341              :         /* shrink at a rate of 2x */
     342              :         n_buckets >>= shrink;
     343              : 
     344              :         /* shrink to zero if empty */
     345              :         n_buckets *= (size != 0);
     346              : 
     347              :         __ASSERT_NO_MSG(new_num_buckets != NULL);
     348              :         __ASSERT_NO_MSG(new_num_buckets != &data->n_buckets);
     349              :         *new_num_buckets = n_buckets;
     350              : 
     351              :         should_grow =
     352              :                 grow && (data->n_buckets == 0 ||
     353              :                          (size + num_reserved) * 100 / data->n_buckets > map->config->load_factor);
     354              :         should_shrink =
     355              :                 shrink && (n_buckets == 0 || (size * 100) / n_buckets <= map->config->load_factor);
     356              : 
     357              :         return should_grow || should_shrink;
     358              : }
     359              : 
     360              : /** @} */
     361              : 
     362              : #ifdef __cplusplus
     363              : }
     364              : #endif
     365              : 
     366              : #endif /* ZEPHYR_INCLUDE_SYS_HASH_MAP_H_ */
        

Generated by: LCOV version 2.0-1