SF: Clean up ftl::SmallMap lookup fallbacks
Avoid std::cref to a local variable, which is not intuitive and incurs
construction in the non-fallback case.
Bug: 185536303
Test: ftl_test
Change-Id: I1c5a94bdab105a04f8230fe762bdc433eea5c97a
diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h
index c5ff03b..c0f6768 100644
--- a/include/ftl/algorithm.h
+++ b/include/ftl/algorithm.h
@@ -68,4 +68,29 @@
return std::cref(pair.second);
}
+// Combinator for ftl::Optional<T>::or_else when T is std::reference_wrapper<const V>. Given a
+// lambda argument that returns a `constexpr` value, ftl::static_ref<T> binds a reference to a
+// static T initialized to that constant.
+//
+// const ftl::SmallMap map = ftl::init::map(13, "tiramisu"sv)(14, "upside-down cake"sv);
+// assert("???"sv ==
+// map.get(20).or_else(ftl::static_ref<std::string_view>([] { return "???"sv; }))->get());
+//
+// using Map = decltype(map);
+//
+// assert("snow cone"sv ==
+// ftl::find_if(map, [](const auto& pair) { return pair.second.front() == 's'; })
+// .transform(ftl::to_mapped_ref<Map>)
+// .or_else(ftl::static_ref<std::string_view>([] { return "snow cone"sv; }))
+// ->get());
+//
+template <typename T, typename F>
+constexpr auto static_ref(F&& f) {
+ return [f = std::forward<F>(f)] {
+ constexpr auto kInitializer = f();
+ static const T kValue = kInitializer;
+ return Optional(std::cref(kValue));
+ };
+}
+
} // namespace android::ftl
diff --git a/libs/ftl/algorithm_test.cpp b/libs/ftl/algorithm_test.cpp
index 8052caf..487b1b8 100644
--- a/libs/ftl/algorithm_test.cpp
+++ b/libs/ftl/algorithm_test.cpp
@@ -47,4 +47,20 @@
EXPECT_EQ(opt->get(), ftl::StaticVector("tiramisu"sv));
}
+TEST(Algorithm, StaticRef) {
+ using namespace std::string_view_literals;
+
+ const ftl::SmallMap map = ftl::init::map(13, "tiramisu"sv)(14, "upside-down cake"sv);
+ ASSERT_EQ("???"sv,
+ map.get(20).or_else(ftl::static_ref<std::string_view>([] { return "???"sv; }))->get());
+
+ using Map = decltype(map);
+
+ ASSERT_EQ("snow cone"sv,
+ ftl::find_if(map, [](const auto& pair) { return pair.second.front() == 's'; })
+ .transform(ftl::to_mapped_ref<Map>)
+ .or_else(ftl::static_ref<std::string_view>([] { return "snow cone"sv; }))
+ ->get());
+}
+
} // namespace android::test
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index ed65bc6..67e1b9c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -22,6 +22,7 @@
#include <string>
#include <android-base/stringprintf.h>
+#include <ftl/algorithm.h>
#include <ftl/small_map.h>
#include <utils/Timers.h>
@@ -82,12 +83,18 @@
flushTime();
TotalTimes totalTimes = ftl::init::map("ScreenOff", mScreenOffTime);
- const auto zero = std::chrono::milliseconds::zero();
// Sum the times for modes that map to the same name, e.g. "60 Hz".
for (const auto& [fps, time] : mFpsTotalTimes) {
const auto string = to_string(fps);
- const auto total = std::as_const(totalTimes).get(string).value_or(std::cref(zero));
+ const auto total = std::as_const(totalTimes)
+ .get(string)
+ .or_else(ftl::static_ref<std::chrono::milliseconds>([] {
+ using namespace std::chrono_literals;
+ return 0ms;
+ }))
+ .value();
+
totalTimes.emplace_or_replace(string, total.get() + time);
}
@@ -114,15 +121,18 @@
mPreviousRecordedTime = currentTime;
const auto duration = std::chrono::milliseconds{ns2ms(timeElapsed)};
- const auto zero = std::chrono::milliseconds::zero();
-
uint32_t fps = 0;
if (mCurrentPowerMode == PowerMode::ON) {
// Normal power mode is counted under different config modes.
const auto total = std::as_const(mFpsTotalTimes)
.get(mCurrentRefreshRate)
- .value_or(std::cref(zero));
+ .or_else(ftl::static_ref<std::chrono::milliseconds>([] {
+ using namespace std::chrono_literals;
+ return 0ms;
+ }))
+ .value();
+
mFpsTotalTimes.emplace_or_replace(mCurrentRefreshRate, total.get() + duration);
fps = static_cast<uint32_t>(mCurrentRefreshRate.getIntValue());
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 720a1cb..4b2983b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -32,6 +32,7 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#include <ftl/algorithm.h>
#include <ftl/fake_guard.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
@@ -438,13 +439,13 @@
RefreshRateSelectorPtr pacesetterSelectorPtrLocked() const REQUIRES(mDisplayLock) {
ftl::FakeGuard guard(kMainThreadContext);
- const RefreshRateSelectorPtr noPacesetter;
return mPacesetterDisplayId
.and_then([this](PhysicalDisplayId pacesetterId)
REQUIRES(mDisplayLock, kMainThreadContext) {
return mRefreshRateSelectors.get(pacesetterId);
})
- .value_or(std::cref(noPacesetter));
+ .or_else(ftl::static_ref<RefreshRateSelectorPtr>([] { return nullptr; }))
+ .value();
}
std::shared_ptr<const VsyncSchedule> getVsyncScheduleLocked(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index eb9dc74..04fcfb9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -28,6 +28,7 @@
#include <android/gui/ISurfaceComposerClient.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
+#include <ftl/algorithm.h>
#include <ftl/future.h>
#include <ftl/non_null.h>
#include <gui/BufferQueue.h>
@@ -854,8 +855,9 @@
}
sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) REQUIRES(mStateLock) {
- const sp<DisplayDevice> nullDisplay;
- return mDisplays.get(displayToken).value_or(std::cref(nullDisplay));
+ return mDisplays.get(displayToken)
+ .or_else(ftl::static_ref<sp<DisplayDevice>>([] { return nullptr; }))
+ .value();
}
sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
@@ -1011,10 +1013,10 @@
*/
sp<display::DisplayToken> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
REQUIRES(mStateLock) {
- const sp<display::DisplayToken> nullToken;
return mPhysicalDisplays.get(displayId)
.transform([](const display::PhysicalDisplay& display) { return display.token(); })
- .value_or(std::cref(nullToken));
+ .or_else([] { return std::optional<sp<display::DisplayToken>>(nullptr); })
+ .value();
}
std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked(