Commit 33849b67 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook GitHub Bot

makeValueObserver

Summary: Helper observer which only triggers updates when the value changes.

Reviewed By: bithree

Differential Revision: D20521319

fbshipit-source-id: 77e45d92f710b1701552cf29445f44aa9d9487f4
parent 7be4309f
......@@ -123,5 +123,32 @@ CallbackHandle Observer<T>::addCallback(
folly::Function<void(Snapshot<T>)> callback) const {
return CallbackHandle(*this, std::move(callback));
}
template <typename T>
Observer<T> makeValueObserver(Observer<T> observer) {
return makeValueObserver(
[observer] { return observer.getSnapshot().getShared(); });
}
template <typename F>
Observer<observer_detail::ResultOf<F>> makeValueObserver(F&& creator) {
return makeValueObserver([creator = std::forward<F>(creator)]() mutable {
return std::make_shared<observer_detail::ResultOf<F>>(creator());
});
}
template <typename F>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeValueObserver(
F&& creator) {
auto activeValue = creator();
return makeObserver([activeValue = std::move(activeValue),
creator = std::forward<F>(creator)]() mutable {
auto newValue = creator();
if (!(*activeValue == *newValue)) {
activeValue = newValue;
}
return activeValue;
});
}
} // namespace observer
} // namespace folly
......@@ -189,6 +189,24 @@ Observer<observer_detail::ResultOf<F>> makeObserver(F&& creator);
template <typename F>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeObserver(F&& creator);
/**
* The returned Observer will proxy updates from the input observer, but will
* skip updates that contain the same (according to operator==) value even if
* the actual object in the update is different.
*/
template <typename T>
Observer<T> makeValueObserver(Observer<T> observer);
/**
* A more efficient short-cut for makeValueObserver(makeObserver(...)).
*/
template <typename F>
Observer<observer_detail::ResultOf<F>> makeValueObserver(F&& creator);
template <typename F>
Observer<observer_detail::ResultOfUnwrapSharedPtr<F>> makeValueObserver(
F&& creator);
template <typename T>
class TLObserver {
public:
......
......@@ -489,3 +489,50 @@ TEST(Observer, Shutdown) {
auto observer = folly::observer::makeObserver([] { return 42; });
EXPECT_EQ(42, **observer);
}
TEST(Observer, MakeValueObserver) {
struct ValueStruct {
ValueStruct(int value, int id) : value_(value), id_(id) {}
bool operator==(const ValueStruct& other) const {
return value_ == other.value_;
}
const int value_;
const int id_;
};
SimpleObservable<ValueStruct> observable(ValueStruct(1, 1));
std::vector<int> observedIds;
std::vector<int> observedValues;
std::vector<int> observedValues2;
auto ch1 = observable.getObserver().addCallback(
[&](auto snapshot) { observedIds.push_back(snapshot->id_); });
auto ch2 = makeValueObserver(observable.getObserver())
.addCallback([&](auto snapshot) {
observedValues.push_back(snapshot->value_);
});
auto ch3 = makeValueObserver(
[observer = observable.getObserver()] { return **observer; })
.addCallback([&](auto snapshot) {
observedValues2.push_back(snapshot->value_);
});
folly::observer_detail::ObserverManager::waitForAllUpdates();
observable.setValue(ValueStruct(1, 2));
folly::observer_detail::ObserverManager::waitForAllUpdates();
observable.setValue(ValueStruct(2, 3));
folly::observer_detail::ObserverManager::waitForAllUpdates();
observable.setValue(ValueStruct(2, 4));
folly::observer_detail::ObserverManager::waitForAllUpdates();
observable.setValue(ValueStruct(3, 5));
folly::observer_detail::ObserverManager::waitForAllUpdates();
EXPECT_EQ(observedIds, std::vector<int>({1, 2, 3, 4, 5}));
EXPECT_EQ(observedValues, std::vector<int>({1, 2, 3}));
EXPECT_EQ(observedValues2, std::vector<int>({1, 2, 3}));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment