Skip to content

Remove folly::EvictingCacheMap #52019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Loading