blob: f392315f722380caae5155ef7861e46a98f3cd02 [file] [edit]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_MEMORY_METRICS_MAS_CACHE_H_
#define SRC_DEVELOPER_MEMORY_METRICS_MAS_CACHE_H_
#include <optional>
#include <unordered_map>
#include <utility>
namespace memory {
// MarkAndSweepCache implements a cache that uses a mark-and-sweep strategy
// to prune entries. It supports O(1) lookup and insertion.
// Thread safety: only safe to use from a single thread.
template <typename Key, typename Value>
class MarkAndSweepCache {
private:
// Wraps the cached value and the mark bit indicating whether the entry
// was recently accessed.
struct Entry {
Value value;
bool marked;
Entry(Value val, bool m) : value(std::move(val)), marked(m) {}
};
std::unordered_map<Key, Entry> map_;
public:
MarkAndSweepCache() = default;
// Returns the value associated with the key if it exists, and marks it as active.
std::optional<Value> Find(const Key& key) {
auto it = map_.find(key);
if (it != map_.end()) {
// Accessing the entry marks it so it survives the next sweep.
it->second.marked = true;
return it->second.value;
}
return std::nullopt;
}
// Inserts the value for the key if not present, and always marks the entry as active.
bool Emplace(Key key, Value value) {
auto [it, inserted] = map_.try_emplace(std::move(key), std::move(value), true);
if (!inserted) {
// If the entry already exists, we do not overwrite the value, but we do
// mark it as active so it survives the next sweep.
it->second.marked = true;
}
return inserted;
}
// Removes the entry for the key if present.
// Returns true if an entry was removed, false otherwise.
bool Erase(const Key& key) { return map_.erase(key) > 0; }
// Removes all entries that have not been marked active since the last sweep.
void Sweep() {
for (auto it = map_.begin(); it != map_.end();) {
if (!it->second.marked) {
it = map_.erase(it);
} else {
// Unmark surviving entries so they must be accessed again to survive
// the subsequent sweep.
it->second.marked = false;
++it;
}
}
}
};
} // namespace memory
#endif // SRC_DEVELOPER_MEMORY_METRICS_MAS_CACHE_H_