Add support for recursive dependency tracking across PropertyTracker instances

By default PropertyTracker::evaluate() registers the currently
evaluating binding/tracker as a dependency. This should help with
repeaters and other scenarios where in the run-time we use property
trackers but want to track the overall "dirtyness" in the window with
regards to whether a redraw is needed or not.

The new evaluate_as_dependency_root() function allows skipping this
mechanism and is used for the two trackers in the window.
This commit is contained in:
Simon Hausmann 2021-03-24 13:51:23 +01:00
parent e63baa5766
commit 3bd5b0eadf
5 changed files with 115 additions and 16 deletions

View file

@ -228,6 +228,22 @@ struct PropertyTracker
return result;
}
template<typename F>
auto evaluate_as_dependency_root(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>
{
cbindgen_private::sixtyfps_property_tracker_evaluate_as_dependency_root(
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
}
template<typename F>
auto evaluate_as_dependency_root(const F &f) const
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
{
decltype(f()) result;
this->evaluate_as_dependency_root([&] { result = f(); });
return result;
}
private:
cbindgen_private::PropertyTrackerOpaque inner;
};

View file

@ -42,3 +42,25 @@ TEST_CASE("Basic SharedVector API", "[vector]")
REQUIRE(vec[2] == 10);
}
}
TEST_CASE("Property Tracker")
{
using namespace sixtyfps;
PropertyTracker tracker1;
PropertyTracker tracker2;
Property<int> prop(42);
auto r = tracker1.evaluate([&]() { return tracker2.evaluate([&]() { return prop.get(); }); });
REQUIRE(r == 42);
prop.set(1);
REQUIRE(tracker2.is_dirty());
REQUIRE(tracker1.is_dirty());
r = tracker1.evaluate(
[&]() { return tracker2.evaluate_as_dependency_root([&]() { return prop.get(); }); });
REQUIRE(r == 1);
prop.set(100);
REQUIRE(tracker2.is_dirty());
REQUIRE(!tracker1.is_dirty());
}