Loading services/surfaceflinger/Promise.h 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * 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. */ #pragma once #include <future> #include <type_traits> #include <utility> namespace android::promise { namespace impl { template <typename T> struct FutureResult { using Type = T; }; template <typename T> struct FutureResult<std::future<T>> { using Type = T; }; } // namespace impl template <typename T> using FutureResult = typename impl::FutureResult<T>::Type; template <typename... Args> inline auto defer(Args... args) { return std::async(std::launch::deferred, std::forward<Args>(args)...); } template <typename T> inline std::future<T> yield(T&& v) { return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v)); } template <typename T> struct Chain { Chain(std::future<T>&& f) : future(std::move(f)) {} operator std::future<T>&&() && { return std::move(future); } T get() && { return future.get(); } template <typename F, typename R = std::invoke_result_t<F, T>> auto then(F&& op) && -> Chain<FutureResult<R>> { return defer( [](auto&& f, F&& op) { R r = op(f.get()); if constexpr (std::is_same_v<R, FutureResult<R>>) { return r; } else { return r.get(); } }, std::move(future), std::forward<F>(op)); } std::future<T> future; }; template <typename T> inline Chain<T> chain(std::future<T>&& f) { return std::move(f); } } // namespace android::promise services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ cc_test { "LayerHistoryTestV2.cpp", "LayerMetadataTest.cpp", "PhaseOffsetsTest.cpp", "PromiseTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", "SetFrameRateTest.cpp", Loading services/surfaceflinger/tests/unittests/PromiseTest.cpp 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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 Loading
services/surfaceflinger/Promise.h 0 → 100644 +80 −0 Original line number Diff line number Diff line /* * 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. */ #pragma once #include <future> #include <type_traits> #include <utility> namespace android::promise { namespace impl { template <typename T> struct FutureResult { using Type = T; }; template <typename T> struct FutureResult<std::future<T>> { using Type = T; }; } // namespace impl template <typename T> using FutureResult = typename impl::FutureResult<T>::Type; template <typename... Args> inline auto defer(Args... args) { return std::async(std::launch::deferred, std::forward<Args>(args)...); } template <typename T> inline std::future<T> yield(T&& v) { return defer([](T&& v) { return std::forward<T>(v); }, std::forward<T>(v)); } template <typename T> struct Chain { Chain(std::future<T>&& f) : future(std::move(f)) {} operator std::future<T>&&() && { return std::move(future); } T get() && { return future.get(); } template <typename F, typename R = std::invoke_result_t<F, T>> auto then(F&& op) && -> Chain<FutureResult<R>> { return defer( [](auto&& f, F&& op) { R r = op(f.get()); if constexpr (std::is_same_v<R, FutureResult<R>>) { return r; } else { return r.get(); } }, std::move(future), std::forward<F>(op)); } std::future<T> future; }; template <typename T> inline Chain<T> chain(std::future<T>&& f) { return std::move(f); } } // namespace android::promise
services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ cc_test { "LayerHistoryTestV2.cpp", "LayerMetadataTest.cpp", "PhaseOffsetsTest.cpp", "PromiseTest.cpp", "SchedulerTest.cpp", "SchedulerUtilsTest.cpp", "SetFrameRateTest.cpp", Loading
services/surfaceflinger/tests/unittests/PromiseTest.cpp 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * 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