forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RuntimeTarget refactor - introduce WeakList for Target→Agent refs
Summary: Changelog: [Internal] Replaces the copypasta'd `PageTarget::forEachSession`, `InstanceTarget::forEachAgent` and `RuntimeTarget::forEachAgent` with a shared utility class for managing a list of `weak_ptr`s. In a `WeakList`, elements can only be added (`insert`), iterated over (`forEach`), and counted (`size`, `empty`). Conceptually, elements are automatically removed from the list as soon as they're destroyed, but internally, space is reclaimed *lazily*: the next time we have a reason to iterate over the underlying list, we delete any pointers that are found to be null. ## Naming This is almost a WeakSet, but we don't bother checking for duplicates, hence "WeakList". Reviewed By: hoxyq Differential Revision: D53671483 fbshipit-source-id: 460bfbaa2b8e821281dc352fed0946f99352c9fc
- Loading branch information
1 parent
d4468fb
commit 2661222
Showing
8 changed files
with
184 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
packages/react-native/ReactCommon/jsinspector-modern/WeakList.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <list> | ||
#include <memory> | ||
|
||
namespace facebook::react::jsinspector_modern { | ||
|
||
/** | ||
* A list that holds weak pointers to objects of type `T`. Null pointers are not | ||
* considered to be in the list. | ||
* | ||
* The list is not thread-safe! The caller is responsible for synchronization. | ||
*/ | ||
template <typename T> | ||
class WeakList { | ||
public: | ||
/** | ||
* Call the given function for every element in the list, ensuring the element | ||
* is not destroyed for the duration of the call. Elements are visited in the | ||
* order they were inserted. | ||
* | ||
* As a side effect, any null pointers in the underlying list (corresponding | ||
* to destroyed elements) will be removed during iteration. | ||
*/ | ||
template <typename Fn> | ||
void forEach(Fn&& fn) const { | ||
for (auto it = ptrs_.begin(); it != ptrs_.end();) { | ||
if (auto ptr = it->lock()) { | ||
fn(*ptr); | ||
++it; | ||
} else { | ||
it = ptrs_.erase(it); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Returns the number of (non-null) elements in the list. The count will only | ||
* remain accurate as long as the list is not modified and elements are | ||
* not destroyed. | ||
* | ||
* As a side effect, any null pointers in the underlying list (corresponding | ||
* to destroyed elements) will be removed during this method. | ||
*/ | ||
size_t size() const { | ||
size_t count{0}; | ||
forEach([&count](const auto&) { ++count; }); | ||
return count; | ||
} | ||
|
||
/** | ||
* Returns true if there are no elements in the list. | ||
* | ||
* As a side effect, any null pointers in the underlying list (corresponding | ||
* to destroyed elements) will be removed during this method. | ||
*/ | ||
bool empty() const { | ||
return !size(); | ||
} | ||
|
||
/** | ||
* Inserts an element into the list. | ||
*/ | ||
void insert(std::weak_ptr<T> ptr) { | ||
ptrs_.push_back(ptr); | ||
} | ||
|
||
private: | ||
mutable std::list<std::weak_ptr<T>> ptrs_; | ||
}; | ||
|
||
} // namespace facebook::react::jsinspector_modern |
91 changes: 91 additions & 0 deletions
91
packages/react-native/ReactCommon/jsinspector-modern/tests/WeakListTest.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* 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 <jsinspector-modern/WeakList.h> | ||
|
||
#include <gmock/gmock.h> | ||
#include <gtest/gtest.h> | ||
|
||
#include <vector> | ||
|
||
using namespace ::testing; | ||
|
||
namespace facebook::react::jsinspector_modern { | ||
|
||
TEST(WeakListTest, Size) { | ||
WeakList<int> list; | ||
EXPECT_EQ(list.size(), 0); | ||
|
||
auto p1 = std::make_shared<int>(1); | ||
list.insert(p1); | ||
EXPECT_EQ(list.size(), 1); | ||
|
||
auto p2 = std::make_shared<int>(2); | ||
list.insert(p2); | ||
EXPECT_EQ(list.size(), 2); | ||
|
||
p1.reset(); | ||
EXPECT_EQ(list.size(), 1); | ||
|
||
p2.reset(); | ||
EXPECT_EQ(list.size(), 0); | ||
} | ||
|
||
TEST(WeakListTest, Empty) { | ||
WeakList<int> list; | ||
EXPECT_EQ(list.empty(), true); | ||
|
||
auto p1 = std::make_shared<int>(1); | ||
list.insert(p1); | ||
EXPECT_EQ(list.empty(), false); | ||
|
||
auto p2 = std::make_shared<int>(2); | ||
list.insert(p2); | ||
EXPECT_EQ(list.empty(), false); | ||
|
||
p1.reset(); | ||
EXPECT_EQ(list.empty(), false); | ||
|
||
p2.reset(); | ||
EXPECT_EQ(list.empty(), true); | ||
} | ||
|
||
TEST(WeakListTest, ForEach) { | ||
WeakList<int> list; | ||
auto p1 = std::make_shared<int>(1); | ||
list.insert(p1); | ||
auto p2 = std::make_shared<int>(2); | ||
list.insert(p2); | ||
auto p3 = std::make_shared<int>(3); | ||
list.insert(p3); | ||
|
||
p2.reset(); | ||
|
||
std::vector<int> visited; | ||
list.forEach([&visited](const int& value) { visited.push_back(value); }); | ||
EXPECT_THAT(visited, ElementsAre(1, 3)); | ||
} | ||
|
||
TEST(WeakListTest, ElementsAreAliveDuringCallback) { | ||
WeakList<int> list; | ||
auto p1 = std::make_shared<int>(1); | ||
// A separate weak_ptr to observe the lifetime of `p1`. | ||
std::weak_ptr wp1 = p1; | ||
list.insert(p1); | ||
|
||
std::vector<int> visited; | ||
list.forEach([&](const int& value) { | ||
p1.reset(); | ||
EXPECT_FALSE(wp1.expired()); | ||
visited.push_back(value); | ||
}); | ||
|
||
EXPECT_TRUE(wp1.expired()); | ||
EXPECT_THAT(visited, ElementsAre(1)); | ||
} | ||
|
||
} // namespace facebook::react::jsinspector_modern |