// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #pragma once #include "td/utils/common.h" #include "td/utils/FlatHashMap.h" #include "td/utils/HashTableUtils.h" #include namespace td { template , class EqT = std::equal_to> class WaitFreeHashMap { static constexpr size_t MAX_STORAGE_COUNT = 1 << 8; static_assert((MAX_STORAGE_COUNT & (MAX_STORAGE_COUNT - 1)) == 0, ""); static constexpr uint32 DEFAULT_STORAGE_SIZE = 1 << 12; FlatHashMap default_map_; struct WaitFreeStorage { WaitFreeHashMap maps_[MAX_STORAGE_COUNT]; }; unique_ptr wait_free_storage_; uint32 hash_mult_ = 1; uint32 max_storage_size_ = DEFAULT_STORAGE_SIZE; uint32 get_wait_free_index(const KeyT &key) const { return randomize_hash(HashT()(key) * hash_mult_) & (MAX_STORAGE_COUNT - 1); } WaitFreeHashMap &get_wait_free_storage(const KeyT &key) { return wait_free_storage_->maps_[get_wait_free_index(key)]; } const WaitFreeHashMap &get_wait_free_storage(const KeyT &key) const { return wait_free_storage_->maps_[get_wait_free_index(key)]; } void split_storage() { CHECK(wait_free_storage_ == nullptr); wait_free_storage_ = make_unique(); uint32 next_hash_mult = hash_mult_ * 1000000007; for (uint32 i = 0; i < MAX_STORAGE_COUNT; i++) { auto &map = wait_free_storage_->maps_[i]; map.hash_mult_ = next_hash_mult; map.max_storage_size_ = DEFAULT_STORAGE_SIZE + i * next_hash_mult % DEFAULT_STORAGE_SIZE; } for (auto &it : default_map_) { get_wait_free_storage(it.first).set(it.first, std::move(it.second)); } default_map_.clear(); } public: void set(const KeyT &key, ValueT value) { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).set(key, std::move(value)); } default_map_[key] = std::move(value); if (default_map_.size() == max_storage_size_) { split_storage(); } } ValueT get(const KeyT &key) const { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).get(key); } auto it = default_map_.find(key); if (it == default_map_.end()) { return {}; } return it->second; } size_t count(const KeyT &key) const { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).count(key); } return default_map_.count(key); } // specialization for WaitFreeHashMap<..., unique_ptr> template typename T::element_type *get_pointer(const KeyT &key) { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).get_pointer(key); } auto it = default_map_.find(key); if (it == default_map_.end()) { return nullptr; } return it->second.get(); } template const typename T::element_type *get_pointer(const KeyT &key) const { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).get_pointer(key); } auto it = default_map_.find(key); if (it == default_map_.end()) { return nullptr; } return it->second.get(); } ValueT &operator[](const KeyT &key) { if (wait_free_storage_ == nullptr) { ValueT &result = default_map_[key]; if (default_map_.size() != max_storage_size_) { return result; } split_storage(); } return get_wait_free_storage(key)[key]; } size_t erase(const KeyT &key) { if (wait_free_storage_ != nullptr) { return get_wait_free_storage(key).erase(key); } return default_map_.erase(key); } void foreach(const std::function &callback) { if (wait_free_storage_ == nullptr) { for (auto &it : default_map_) { callback(it.first, it.second); } return; } for (auto &it : wait_free_storage_->maps_) { it.foreach(callback); } } void foreach(const std::function &callback) const { if (wait_free_storage_ == nullptr) { for (auto &it : default_map_) { callback(it.first, it.second); } return; } for (auto &it : wait_free_storage_->maps_) { it.foreach(callback); } } size_t calc_size() const { if (wait_free_storage_ == nullptr) { return default_map_.size(); } size_t result = 0; for (size_t i = 0; i < MAX_STORAGE_COUNT; i++) { result += wait_free_storage_->maps_[i].calc_size(); } return result; } bool empty() const { if (wait_free_storage_ == nullptr) { return default_map_.empty(); } for (size_t i = 0; i < MAX_STORAGE_COUNT; i++) { if (!wait_free_storage_->maps_[i].empty()) { return false; } } return true; } }; } // namespace td