|  | /* | 
|  | * Copyright (c) 2022 Meta | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <memory> | 
|  | #include <unordered_map> | 
|  |  | 
|  | #include <zephyr/sys/hash_map.h> | 
|  | #include <zephyr/sys/hash_map_cxx.h> | 
|  |  | 
|  | using cxx_map = std::unordered_map<uint64_t, uint64_t>; | 
|  |  | 
|  | static void sys_hashmap_cxx_iter_next(struct sys_hashmap_iterator *it) | 
|  | { | 
|  | cxx_map *umap = static_cast<cxx_map *>(it->map->data->buckets); | 
|  |  | 
|  | __ASSERT_NO_MSG(umap != nullptr); | 
|  |  | 
|  | __ASSERT(it->size == it->map->data->size, "Concurrent modification!"); | 
|  | __ASSERT(sys_hashmap_iterator_has_next(it), "Attempt to access beyond current bound!"); | 
|  |  | 
|  | auto it2 = umap->begin(); | 
|  | for (size_t i = 0; i < it->pos; ++i, it2++) | 
|  | ; | 
|  |  | 
|  | it->key = it2->first; | 
|  | it->value = it2->second; | 
|  | ++it->pos; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * C++ Wrapped Hashmap API | 
|  | */ | 
|  |  | 
|  | static void sys_hashmap_cxx_iter(const struct sys_hashmap *map, struct sys_hashmap_iterator *it) | 
|  | { | 
|  | it->map = map; | 
|  | it->next = sys_hashmap_cxx_iter_next; | 
|  | it->state = nullptr; | 
|  | it->key = 0; | 
|  | it->value = 0; | 
|  | it->pos = 0; | 
|  | *((size_t *)&it->size) = map->data->size; | 
|  | } | 
|  |  | 
|  | static void sys_hashmap_cxx_clear(struct sys_hashmap *map, sys_hashmap_callback_t cb, void *cookie) | 
|  | { | 
|  | cxx_map *umap = static_cast<cxx_map *>(map->data->buckets); | 
|  |  | 
|  | if (umap == nullptr) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cb != nullptr) { | 
|  | for (auto &kv : *umap) { | 
|  | cb(kv.first, kv.second, cookie); | 
|  | } | 
|  | } | 
|  |  | 
|  | delete umap; | 
|  |  | 
|  | map->data->buckets = nullptr; | 
|  | map->data->n_buckets = 0; | 
|  | map->data->size = 0; | 
|  | } | 
|  |  | 
|  | static int sys_hashmap_cxx_insert(struct sys_hashmap *map, uint64_t key, uint64_t value, | 
|  | uint64_t *old_value) | 
|  | { | 
|  | cxx_map *umap = static_cast<cxx_map *>(map->data->buckets); | 
|  |  | 
|  | if (umap == nullptr) { | 
|  | umap = new cxx_map; | 
|  | umap->max_load_factor(map->config->load_factor / 100.0f); | 
|  | map->data->buckets = umap; | 
|  | } | 
|  |  | 
|  | auto it = umap->find(key); | 
|  | if (it != umap->end() && old_value != nullptr) { | 
|  | *old_value = it->second; | 
|  | it->second = value; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | try { | 
|  | (*umap)[key] = value; | 
|  | } catch(...) { | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | ++map->data->size; | 
|  | map->data->n_buckets = umap->bucket_count(); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static bool sys_hashmap_cxx_remove(struct sys_hashmap *map, uint64_t key, uint64_t *value) | 
|  | { | 
|  | cxx_map *umap = static_cast<cxx_map *>(map->data->buckets); | 
|  |  | 
|  | if (umap == nullptr) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | auto it = umap->find(key); | 
|  | if (it == umap->end()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (value != nullptr) { | 
|  | *value = it->second; | 
|  | } | 
|  |  | 
|  | umap->erase(key); | 
|  | --map->data->size; | 
|  | map->data->n_buckets = umap->bucket_count(); | 
|  |  | 
|  | if (map->data->size == 0) { | 
|  | delete umap; | 
|  | map->data->n_buckets = 0; | 
|  | map->data->buckets = nullptr; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool sys_hashmap_cxx_get(const struct sys_hashmap *map, uint64_t key, uint64_t *value) | 
|  | { | 
|  | cxx_map *umap = static_cast<cxx_map *>(map->data->buckets); | 
|  |  | 
|  | if (umap == nullptr) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | auto it = umap->find(key); | 
|  | if (it == umap->end()) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (value != nullptr) { | 
|  | *value = it->second; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | extern "C" { | 
|  | const struct sys_hashmap_api sys_hashmap_cxx_api = { | 
|  | .iter = sys_hashmap_cxx_iter, | 
|  | .clear = sys_hashmap_cxx_clear, | 
|  | .insert = sys_hashmap_cxx_insert, | 
|  | .remove = sys_hashmap_cxx_remove, | 
|  | .get = sys_hashmap_cxx_get, | 
|  | }; | 
|  | } |