158 lines
3.1 KiB
C++
158 lines
3.1 KiB
C++
/*
|
|
* 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,
|
|
};
|
|
}
|