Skip to content

Commit bf1923a

Browse files
Remove folly::EvictingCacheMap (facebook#52019)
Summary: Pull Request resolved: facebook#52019 Replace folly::EvictionMap with pure std implementation changelog: [internal] Reviewed By: javache, sammy-SC Differential Revision: D76631579
1 parent f6b7bd9 commit bf1923a

File tree

2 files changed

+70
-26
lines changed

2 files changed

+70
-26
lines changed

packages/react-native/ReactCommon/react/utils/SimpleThreadSafeCache.h

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
#pragma once
99

1010
#include <concepts>
11+
#include <list>
1112
#include <mutex>
12-
#include <optional>
13-
#include <type_traits>
14-
15-
#include <folly/container/EvictingCacheMap.h>
13+
#include <unordered_map>
1614

1715
namespace facebook::react {
1816

@@ -26,8 +24,8 @@ concept CacheGeneratorFunction = std::invocable<GeneratorT> &&
2624
template <typename KeyT, typename ValueT, int maxSize>
2725
class SimpleThreadSafeCache {
2826
public:
29-
SimpleThreadSafeCache() : map_{maxSize} {}
30-
SimpleThreadSafeCache(unsigned long size) : map_{size} {}
27+
SimpleThreadSafeCache() : maxSize_(maxSize) {}
28+
SimpleThreadSafeCache(unsigned long size) : maxSize_{size} {}
3129

3230
/*
3331
* Returns a value from the map with a given key.
@@ -38,14 +36,23 @@ class SimpleThreadSafeCache {
3836
ValueT get(const KeyT& key, CacheGeneratorFunction<ValueT> auto generator)
3937
const {
4038
std::lock_guard<std::mutex> lock(mutex_);
41-
auto iterator = map_.find(key);
42-
if (iterator == map_.end()) {
43-
auto value = generator();
44-
map_.set(key, value);
45-
return value;
39+
40+
if (auto it = map_.find(key); it != map_.end()) {
41+
// Move accessed item to front of list
42+
list_.splice(list_.begin(), list_, it->second);
43+
return it->second->second;
4644
}
4745

48-
return iterator->second;
46+
auto value = generator();
47+
// Add new value to front of list and map
48+
list_.emplace_front(key, value);
49+
map_[key] = list_.begin();
50+
if (list_.size() > maxSize_) {
51+
// Evict least recently used item (back of list)
52+
map_.erase(list_.back().first);
53+
list_.pop_back();
54+
}
55+
return value;
4956
}
5057

5158
/*
@@ -55,26 +62,23 @@ class SimpleThreadSafeCache {
5562
*/
5663
std::optional<ValueT> get(const KeyT& key) const {
5764
std::lock_guard<std::mutex> lock(mutex_);
58-
auto iterator = map_.find(key);
59-
if (iterator == map_.end()) {
60-
return {};
65+
66+
if (auto it = map_.find(key); it != map_.end()) {
67+
// Move accessed item to front of list
68+
list_.splice(list_.begin(), list_, it->second);
69+
return it->second->second;
6170
}
6271

63-
return iterator->second;
64-
}
65-
66-
/*
67-
* Sets a key-value pair in the LRU cache.
68-
* Can be called from any thread.
69-
*/
70-
void set(const KeyT& key, const ValueT& value) const {
71-
std::lock_guard<std::mutex> lock(mutex_);
72-
map_.set(std::move(key), std::move(value));
72+
return ValueT{};
7373
}
7474

7575
private:
76-
mutable folly::EvictingCacheMap<KeyT, ValueT> map_;
76+
using iterator = typename std::list<std::pair<KeyT, ValueT>>::iterator;
77+
78+
size_t maxSize_;
7779
mutable std::mutex mutex_;
80+
mutable std::list<std::pair<KeyT, ValueT>> list_;
81+
mutable std::unordered_map<KeyT, iterator> map_;
7882
};
7983

8084
} // namespace facebook::react
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include <gtest/gtest.h>
9+
#include <react/utils/SimpleThreadSafeCache.h>
10+
11+
namespace facebook::react {
12+
13+
TEST(EvictingCacheMapTest, BasicInsertAndGet) {
14+
SimpleThreadSafeCache<int, std::string, 3> cache;
15+
EXPECT_EQ(cache.get(1), ""); // Default constructed value is returned
16+
EXPECT_EQ(cache.get(2), ""); // Default constructed value is returned
17+
EXPECT_EQ(cache.get(3), ""); // Default constructed value is returned
18+
19+
cache.get(1, []() { return std::string("one"); });
20+
cache.get(2, []() { return std::string("two"); });
21+
cache.get(3, []() { return std::string("three"); });
22+
EXPECT_EQ(cache.get(1), "one");
23+
EXPECT_EQ(cache.get(2), "two");
24+
EXPECT_EQ(cache.get(3), "three");
25+
}
26+
27+
TEST(EvictingCacheMapTest, Eviction) {
28+
SimpleThreadSafeCache<int, std::string, 2> cache;
29+
cache.get(1, []() { return std::string("one"); });
30+
cache.get(2, []() { return std::string("two"); });
31+
cache.get(3, []() { return std::string("three"); }); // should evict key 1
32+
33+
EXPECT_EQ(
34+
cache.get(1),
35+
""); // key 1 should be evicted and default constructed value is returned
36+
EXPECT_EQ(cache.get(2), "two");
37+
EXPECT_EQ(cache.get(3), "three");
38+
}
39+
40+
} // namespace facebook::react

0 commit comments

Comments
 (0)