Remove folly::EvictingCacheMap (#52019)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/52019

Replace folly::EvictionMap with pure std implementation

changelog: [internal][Breaking] Remove unused set() method of SimpleThreadSafeCache

Reviewed By: javache, sammy-SC

Differential Revision: D76631579

fbshipit-source-id: 15dfa8a8c0d2809440c214a72e48def6e1dba2f0
This commit is contained in:
Christoph Purrer
2025-06-16 15:06:17 -07:00
committed by Facebook GitHub Bot
parent 2528e48e93
commit 089fb10740
2 changed files with 71 additions and 26 deletions
@@ -8,11 +8,9 @@
#pragma once
#include <concepts>
#include <list>
#include <mutex>
#include <optional>
#include <type_traits>
#include <folly/container/EvictingCacheMap.h>
#include <unordered_map>
namespace facebook::react {
@@ -26,8 +24,8 @@ concept CacheGeneratorFunction = std::invocable<GeneratorT> &&
template <typename KeyT, typename ValueT, int maxSize>
class SimpleThreadSafeCache {
public:
SimpleThreadSafeCache() : map_{maxSize} {}
SimpleThreadSafeCache(unsigned long size) : map_{size} {}
SimpleThreadSafeCache() : maxSize_(maxSize) {}
SimpleThreadSafeCache(unsigned long size) : maxSize_{size} {}
/*
* Returns a value from the map with a given key.
@@ -38,14 +36,23 @@ class SimpleThreadSafeCache {
ValueT get(const KeyT& key, CacheGeneratorFunction<ValueT> auto generator)
const {
std::lock_guard<std::mutex> lock(mutex_);
auto iterator = map_.find(key);
if (iterator == map_.end()) {
auto value = generator();
map_.set(key, value);
return value;
if (auto it = map_.find(key); it != map_.end()) {
// Move accessed item to front of list
list_.splice(list_.begin(), list_, it->second);
return it->second->second;
}
return iterator->second;
auto value = generator();
// Add new value to front of list and map
list_.emplace_front(key, value);
map_[key] = list_.begin();
if (list_.size() > maxSize_) {
// Evict least recently used item (back of list)
map_.erase(list_.back().first);
list_.pop_back();
}
return value;
}
/*
@@ -55,26 +62,24 @@ class SimpleThreadSafeCache {
*/
std::optional<ValueT> get(const KeyT& key) const {
std::lock_guard<std::mutex> lock(mutex_);
auto iterator = map_.find(key);
if (iterator == map_.end()) {
return {};
if (auto it = map_.find(key); it != map_.end()) {
// Move accessed item to front of list
list_.splice(list_.begin(), list_, it->second);
return it->second->second;
}
return iterator->second;
}
/*
* Sets a key-value pair in the LRU cache.
* Can be called from any thread.
*/
void set(const KeyT& key, const ValueT& value) const {
std::lock_guard<std::mutex> lock(mutex_);
map_.set(std::move(key), std::move(value));
return ValueT{};
}
private:
mutable folly::EvictingCacheMap<KeyT, ValueT> map_;
using EntryT = std::pair<KeyT, ValueT>;
using iterator = typename std::list<EntryT>::iterator;
size_t maxSize_;
mutable std::mutex mutex_;
mutable std::list<EntryT> list_;
mutable std::unordered_map<KeyT, iterator> map_;
};
} // namespace facebook::react
@@ -0,0 +1,40 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <gtest/gtest.h>
#include <react/utils/SimpleThreadSafeCache.h>
namespace facebook::react {
TEST(EvictingCacheMapTest, BasicInsertAndGet) {
SimpleThreadSafeCache<int, std::string, 3> cache;
EXPECT_EQ(cache.get(1), ""); // Default constructed value is returned
EXPECT_EQ(cache.get(2), ""); // Default constructed value is returned
EXPECT_EQ(cache.get(3), ""); // Default constructed value is returned
cache.get(1, []() { return std::string("one"); });
cache.get(2, []() { return std::string("two"); });
cache.get(3, []() { return std::string("three"); });
EXPECT_EQ(cache.get(1), "one");
EXPECT_EQ(cache.get(2), "two");
EXPECT_EQ(cache.get(3), "three");
}
TEST(EvictingCacheMapTest, Eviction) {
SimpleThreadSafeCache<int, std::string, 2> cache;
cache.get(1, []() { return std::string("one"); });
cache.get(2, []() { return std::string("two"); });
cache.get(3, []() { return std::string("three"); }); // should evict key 1
EXPECT_EQ(
cache.get(1),
""); // key 1 should be evicted and default constructed value is returned
EXPECT_EQ(cache.get(2), "two");
EXPECT_EQ(cache.get(3), "three");
}
} // namespace facebook::react