lib/MapCache.h (84 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #pragma once #include <deque> #include <functional> #include <unordered_map> #include <vector> namespace pulsar { // A map cache that supports removing the first N oldest entries from the map. // Value must be moveable and have the default constructor. template <typename Key, typename Value> class MapCache { std::unordered_map<Key, Value> map_; std::deque<Key> keys_; public: using const_iterator = typename decltype(map_)::const_iterator; using iterator = typename decltype(map_)::iterator; MapCache() = default; // Here we don't use =default to be compatible with GCC 4.8 MapCache(MapCache&& rhs) noexcept : map_(std::move(rhs.map_)), keys_(std::move(rhs.keys_)) {} size_t size() const noexcept { return map_.size(); } const_iterator find(const Key& key) const { return map_.find(key); } iterator find(const Key& key) { return map_.find(key); } const_iterator end() const noexcept { return map_.end(); } iterator end() noexcept { return map_.end(); } iterator putIfAbsent(const Key& key, Value&& value) { auto it = map_.find(key); if (it == map_.end()) { keys_.push_back(key); return map_.emplace(key, std::move(value)).first; } else { return end(); } } void removeOldestValues(size_t numToRemove, const std::function<void(const Key&, const Value&)>& callback) { for (size_t i = 0; !keys_.empty() && i < numToRemove; i++) { const auto key = keys_.front(); auto it = map_.find(key); if (it != map_.end()) { if (callback) { callback(it->first, it->second); } map_.erase(it); } keys_.pop_front(); } } void removeOldestValuesIf(const std::function<bool(const Key&, const Value&)>& condition) { if (!condition) return; while (!keys_.empty()) { const auto key = keys_.front(); auto it = map_.find(key); if (it == map_.end()) { continue; } if (condition(it->first, it->second)) { map_.erase(it); keys_.pop_front(); } else { return; } } } void remove(const Key& key) { auto it = map_.find(key); if (it != map_.end()) { removeKeyFromKeys(key); map_.erase(it); } } // Following methods are only used for tests std::vector<Key> getKeys() const { std::vector<Key> keys; for (auto key : keys_) { keys.emplace_back(key); } return keys; } private: void removeKeyFromKeys(const Key& key) { for (auto it = keys_.begin(); it != keys_.end(); ++it) { if (*it == key) { keys_.erase(it); break; } } } }; } // namespace pulsar