SF: Add promise/future utilities
promise::defer and promise::yield return a deferred future given a
lambda or value, respectively. promise::chain enables composition
of sequential futures.
Bug: 123715322
Bug: 134772048
Test: PromiseTest
Change-Id: Iff81407d60a357d76b5863c4a3a8af7760bd8c33
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2f2fb20..7574ff1 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -48,6 +48,7 @@
"LayerHistoryTestV2.cpp",
"LayerMetadataTest.cpp",
"PhaseOffsetsTest.cpp",
+ "PromiseTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
"SetFrameRateTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
new file mode 100644
index 0000000..e4dc1fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "Promise.h"
+
+namespace android {
+namespace {
+
+using Bytes = std::vector<uint8_t>;
+
+Bytes decrement(Bytes bytes) {
+ std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; });
+ return bytes;
+}
+
+} // namespace
+
+TEST(PromiseTest, yield) {
+ EXPECT_EQ(42, promise::yield(42).get());
+
+ auto ptr = std::make_unique<char>('!');
+ auto future = promise::yield(std::move(ptr));
+ EXPECT_EQ('!', *future.get());
+}
+
+TEST(PromiseTest, chain) {
+ std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; });
+
+ std::packaged_task<Bytes(std::string)> appendString([](std::string str) {
+ str += "!xpsme";
+ return Bytes{str.begin(), str.end()};
+ });
+
+ std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes(
+ [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); });
+
+ auto fetch = fetchString.get_future();
+ std::thread fetchThread(std::move(fetchString));
+
+ std::thread appendThread, decrementThread;
+
+ EXPECT_EQ("hello, world",
+ promise::chain(std::move(fetch))
+ .then([](const char* str) { return std::string(str); })
+ .then([&](std::string str) {
+ auto append = appendString.get_future();
+ appendThread = std::thread(std::move(appendString), std::move(str));
+ return append;
+ })
+ .then([&](Bytes bytes) {
+ auto decrement = decrementBytes.get_future();
+ decrementThread = std::thread(std::move(decrementBytes),
+ std::move(bytes));
+ return decrement;
+ })
+ .then([](std::future<Bytes> bytes) { return bytes; })
+ .then([](const Bytes& bytes) {
+ return std::string(bytes.begin(), bytes.end());
+ })
+ .get());
+
+ fetchThread.join();
+ appendThread.join();
+ decrementThread.join();
+}
+
+} // namespace android