Loading include/ftl/small_map.h +14 −38 Original line number Diff line number Diff line Loading @@ -17,11 +17,11 @@ #pragma once #include <ftl/initializer_list.h> #include <ftl/optional.h> #include <ftl/small_vector.h> #include <algorithm> #include <functional> #include <optional> #include <type_traits> #include <utility> Loading @@ -47,7 +47,7 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); // assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // assert(map.get(42).transform([](const std::string& s) { return s.size(); }) == 3u); // // const auto opt = map.get(-1); // assert(opt); Loading @@ -59,7 +59,7 @@ namespace android::ftl { // map.emplace_or_replace(0, "vanilla", 2u, 3u); // assert(map.dynamic()); // // assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); // assert(map == SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); // template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { Loading Loading @@ -123,9 +123,7 @@ class SmallMap final { const_iterator cend() const { return map_.cend(); } // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { return get(key, [](const mapped_type&) {}); } bool contains(const key_type& key) const { return get(key).has_value(); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // Loading @@ -139,46 +137,24 @@ class SmallMap final { // ref.get() = 'D'; // assert(d == 'D'); // auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { return get(key, [](const mapped_type& v) { return std::cref(v); }); auto get(const key_type& key) const -> Optional<std::reference_wrapper<const mapped_type>> { for (const auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { return std::cref(v); } auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { return get(key, [](mapped_type& v) { return std::ref(v); }); } return {}; } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value // for the given key, or std::nullopt if the key was not found. If F has a return type of void, // then the Boolean result indicates whether the key was found. // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>> auto get(const key_type& key, F f) const -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { auto get(const key_type& key) -> Optional<std::reference_wrapper<mapped_type>> { for (auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { if constexpr (std::is_void_v<R>) { f(v); return true; } else { return f(v); } return std::ref(v); } } return {}; } template <typename F> auto get(const key_type& key, F f) { return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); }); } // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); } iterator find(const key_type& key) { return find(key, begin()); } Loading Loading @@ -286,7 +262,7 @@ bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs for (const auto& [k, v] : lhs) { const auto& lv = v; if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { if (!rhs.get(k).transform([&lv](const W& rv) { return lv == rv; }).value_or(false)) { return false; } } Loading include/ftl/unit.h 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <type_traits> #include <utility> namespace android::ftl { // The unit type, and its only value. constexpr struct Unit { } unit; constexpr bool operator==(Unit, Unit) { return true; } constexpr bool operator!=(Unit, Unit) { return false; } // Adapts a function object F to return Unit. The return value of F is ignored. // // As a practical use, the function passed to ftl::Optional<T>::transform is not allowed to return // void (cf. https://wg21.link/P0798R8#mapping-functions-returning-void), but may return Unit if // only its side effects are meaningful: // // ftl::Optional opt = "food"s; // opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); })); // assert(opt == "foo"s); // template <typename F> struct UnitFn { F f; template <typename... Args> Unit operator()(Args&&... args) { return f(std::forward<Args>(args)...), unit; } }; template <typename F> constexpr auto unit_fn(F&& f) -> UnitFn<std::decay_t<F>> { return {std::forward<F>(f)}; } } // namespace android::ftl libs/ftl/optional_test.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <ftl/optional.h> #include <ftl/static_vector.h> #include <ftl/string.h> #include <ftl/unit.h> #include <gtest/gtest.h> #include <functional> Loading Loading @@ -62,6 +63,13 @@ TEST(Optional, Transform) { EXPECT_EQ(out, "abc"s); } // No return value. { Optional opt = "food"s; EXPECT_EQ(ftl::unit, opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); }))); EXPECT_EQ(opt, "foo"s); } // Chaining. EXPECT_EQ(14u, Optional(StaticVector{"upside"s, "down"s}) .transform([](StaticVector<std::string, 3>&& v) { Loading libs/ftl/small_map_test.cpp +17 −13 Original line number Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ #include <ftl/small_map.h> #include <ftl/unit.h> #include <gtest/gtest.h> #include <cctype> #include <string> #include <string_view> using namespace std::string_literals; using namespace std::string_view_literals; namespace android::test { Loading @@ -38,7 +41,7 @@ TEST(SmallMap, Example) { EXPECT_TRUE(map.contains(123)); EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u); EXPECT_EQ(map.get(42).transform([](const std::string& s) { return s.size(); }), 3u); const auto opt = map.get(-1); ASSERT_TRUE(opt); Loading @@ -50,7 +53,7 @@ TEST(SmallMap, Example) { map.emplace_or_replace(0, "vanilla", 2u, 3u); EXPECT_TRUE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); } TEST(SmallMap, Construct) { Loading @@ -70,7 +73,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc")(456, "def")(789, "ghi"))); EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc"sv)(456, "def"sv)(789, "ghi"sv))); } { // In-place constructor with different types. Loading @@ -81,7 +84,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???")(123, "abc")(-1, "\0\0\0"))); EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???"sv)(123, "abc"sv)(-1, ""sv))); } { // In-place constructor with implicit size. Loading @@ -92,7 +95,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 3u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "\0\0\0")(42, "???")(123, "abc"))); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""sv)(42, "???"sv)(123, "abc"sv))); } } Loading @@ -108,7 +111,7 @@ TEST(SmallMap, Assign) { { // Convertible types; same capacity. SmallMap map1 = ftl::init::map<char, std::string>('M', "mega")('G', "giga"); const SmallMap map2 = ftl::init::map('T', "tera")('P', "peta"); const SmallMap map2 = ftl::init::map('T', "tera"sv)('P', "peta"sv); map1 = map2; EXPECT_EQ(map1, map2); Loading Loading @@ -147,7 +150,7 @@ TEST(SmallMap, UniqueKeys) { } } TEST(SmallMap, Find) { TEST(SmallMap, Get) { { // Constant reference. const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); Loading @@ -172,14 +175,15 @@ TEST(SmallMap, Find) { EXPECT_EQ(d, 'D'); } { // Constant unary operation. // Immutable transform operation. const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z'); EXPECT_EQ(map.get('c').transform([](char c) { return std::toupper(c); }), 'Z'); } { // Mutable unary operation. // Mutable transform operation. SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); })); EXPECT_EQ(map.get('c').transform(ftl::unit_fn([](char& c) { c = std::toupper(c); })), ftl::unit); EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x'))); } Loading Loading @@ -247,7 +251,7 @@ TEST(SmallMap, TryReplace) { } { // Replacement arguments can refer to the replaced mapping. const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. Loading Loading @@ -292,7 +296,7 @@ TEST(SmallMap, EmplaceOrReplace) { } { // Replacement arguments can refer to the replaced mapping. const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. Loading services/surfaceflinger/SurfaceFlinger.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -3247,10 +3247,11 @@ void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; const auto opt = displayInputInfos.get(layer->getLayerStack(), [](const auto& info) -> Layer::InputDisplayArgs { return {&info.transform, info.isSecure}; const auto opt = displayInputInfos.get(layer->getLayerStack()) .transform([](const DisplayDevice::InputInfo& info) { return Layer::InputDisplayArgs{&info.transform, info.isSecure}; }); outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{}))); }); Loading Loading
include/ftl/small_map.h +14 −38 Original line number Diff line number Diff line Loading @@ -17,11 +17,11 @@ #pragma once #include <ftl/initializer_list.h> #include <ftl/optional.h> #include <ftl/small_vector.h> #include <algorithm> #include <functional> #include <optional> #include <type_traits> #include <utility> Loading @@ -47,7 +47,7 @@ namespace android::ftl { // assert(!map.dynamic()); // // assert(map.contains(123)); // assert(map.get(42, [](const std::string& s) { return s.size(); }) == 3u); // assert(map.get(42).transform([](const std::string& s) { return s.size(); }) == 3u); // // const auto opt = map.get(-1); // assert(opt); Loading @@ -59,7 +59,7 @@ namespace android::ftl { // map.emplace_or_replace(0, "vanilla", 2u, 3u); // assert(map.dynamic()); // // assert(map == SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); // assert(map == SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); // template <typename K, typename V, std::size_t N, typename KeyEqual = std::equal_to<K>> class SmallMap final { Loading Loading @@ -123,9 +123,7 @@ class SmallMap final { const_iterator cend() const { return map_.cend(); } // Returns whether a mapping exists for the given key. bool contains(const key_type& key) const { return get(key, [](const mapped_type&) {}); } bool contains(const key_type& key) const { return get(key).has_value(); } // Returns a reference to the value for the given key, or std::nullopt if the key was not found. // Loading @@ -139,46 +137,24 @@ class SmallMap final { // ref.get() = 'D'; // assert(d == 'D'); // auto get(const key_type& key) const -> std::optional<std::reference_wrapper<const mapped_type>> { return get(key, [](const mapped_type& v) { return std::cref(v); }); auto get(const key_type& key) const -> Optional<std::reference_wrapper<const mapped_type>> { for (const auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { return std::cref(v); } auto get(const key_type& key) -> std::optional<std::reference_wrapper<mapped_type>> { return get(key, [](mapped_type& v) { return std::ref(v); }); } return {}; } // Returns the result R of a unary operation F on (a constant or mutable reference to) the value // for the given key, or std::nullopt if the key was not found. If F has a return type of void, // then the Boolean result indicates whether the key was found. // // ftl::SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); // // assert(map.get('c', [](char c) { return std::toupper(c); }) == 'Z'); // assert(map.get('c', [](char& c) { c = std::toupper(c); })); // template <typename F, typename R = std::invoke_result_t<F, const mapped_type&>> auto get(const key_type& key, F f) const -> std::conditional_t<std::is_void_v<R>, bool, std::optional<R>> { auto get(const key_type& key) -> Optional<std::reference_wrapper<mapped_type>> { for (auto& [k, v] : *this) { if (KeyEqual{}(k, key)) { if constexpr (std::is_void_v<R>) { f(v); return true; } else { return f(v); } return std::ref(v); } } return {}; } template <typename F> auto get(const key_type& key, F f) { return std::as_const(*this).get( key, [&f](const mapped_type& v) { return f(const_cast<mapped_type&>(v)); }); } // Returns an iterator to an existing mapping for the given key, or the end() iterator otherwise. const_iterator find(const key_type& key) const { return const_cast<SmallMap&>(*this).find(key); } iterator find(const key_type& key) { return find(key, begin()); } Loading Loading @@ -286,7 +262,7 @@ bool operator==(const SmallMap<K, V, N, E>& lhs, const SmallMap<Q, W, M, E>& rhs for (const auto& [k, v] : lhs) { const auto& lv = v; if (!rhs.get(k, [&lv](const auto& rv) { return lv == rv; }).value_or(false)) { if (!rhs.get(k).transform([&lv](const W& rv) { return lv == rv; }).value_or(false)) { return false; } } Loading
include/ftl/unit.h 0 → 100644 +61 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <type_traits> #include <utility> namespace android::ftl { // The unit type, and its only value. constexpr struct Unit { } unit; constexpr bool operator==(Unit, Unit) { return true; } constexpr bool operator!=(Unit, Unit) { return false; } // Adapts a function object F to return Unit. The return value of F is ignored. // // As a practical use, the function passed to ftl::Optional<T>::transform is not allowed to return // void (cf. https://wg21.link/P0798R8#mapping-functions-returning-void), but may return Unit if // only its side effects are meaningful: // // ftl::Optional opt = "food"s; // opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); })); // assert(opt == "foo"s); // template <typename F> struct UnitFn { F f; template <typename... Args> Unit operator()(Args&&... args) { return f(std::forward<Args>(args)...), unit; } }; template <typename F> constexpr auto unit_fn(F&& f) -> UnitFn<std::decay_t<F>> { return {std::forward<F>(f)}; } } // namespace android::ftl
libs/ftl/optional_test.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <ftl/optional.h> #include <ftl/static_vector.h> #include <ftl/string.h> #include <ftl/unit.h> #include <gtest/gtest.h> #include <functional> Loading Loading @@ -62,6 +63,13 @@ TEST(Optional, Transform) { EXPECT_EQ(out, "abc"s); } // No return value. { Optional opt = "food"s; EXPECT_EQ(ftl::unit, opt.transform(ftl::unit_fn([](std::string& str) { str.pop_back(); }))); EXPECT_EQ(opt, "foo"s); } // Chaining. EXPECT_EQ(14u, Optional(StaticVector{"upside"s, "down"s}) .transform([](StaticVector<std::string, 3>&& v) { Loading
libs/ftl/small_map_test.cpp +17 −13 Original line number Diff line number Diff line Loading @@ -15,12 +15,15 @@ */ #include <ftl/small_map.h> #include <ftl/unit.h> #include <gtest/gtest.h> #include <cctype> #include <string> #include <string_view> using namespace std::string_literals; using namespace std::string_view_literals; namespace android::test { Loading @@ -38,7 +41,7 @@ TEST(SmallMap, Example) { EXPECT_TRUE(map.contains(123)); EXPECT_EQ(map.get(42, [](const std::string& s) { return s.size(); }), 3u); EXPECT_EQ(map.get(42).transform([](const std::string& s) { return s.size(); }), 3u); const auto opt = map.get(-1); ASSERT_TRUE(opt); Loading @@ -50,7 +53,7 @@ TEST(SmallMap, Example) { map.emplace_or_replace(0, "vanilla", 2u, 3u); EXPECT_TRUE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz")(0, "nil")(42, "???")(123, "abc"))); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "xyz"sv)(0, "nil"sv)(42, "???"sv)(123, "abc"sv))); } TEST(SmallMap, Construct) { Loading @@ -70,7 +73,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc")(456, "def")(789, "ghi"))); EXPECT_EQ(map, SmallMap(ftl::init::map(123, "abc"sv)(456, "def"sv)(789, "ghi"sv))); } { // In-place constructor with different types. Loading @@ -81,7 +84,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 5u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???")(123, "abc")(-1, "\0\0\0"))); EXPECT_EQ(map, SmallMap(ftl::init::map(42, "???"sv)(123, "abc"sv)(-1, ""sv))); } { // In-place constructor with implicit size. Loading @@ -92,7 +95,7 @@ TEST(SmallMap, Construct) { EXPECT_EQ(map.max_size(), 3u); EXPECT_FALSE(map.dynamic()); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, "\0\0\0")(42, "???")(123, "abc"))); EXPECT_EQ(map, SmallMap(ftl::init::map(-1, ""sv)(42, "???"sv)(123, "abc"sv))); } } Loading @@ -108,7 +111,7 @@ TEST(SmallMap, Assign) { { // Convertible types; same capacity. SmallMap map1 = ftl::init::map<char, std::string>('M', "mega")('G', "giga"); const SmallMap map2 = ftl::init::map('T', "tera")('P', "peta"); const SmallMap map2 = ftl::init::map('T', "tera"sv)('P', "peta"sv); map1 = map2; EXPECT_EQ(map1, map2); Loading Loading @@ -147,7 +150,7 @@ TEST(SmallMap, UniqueKeys) { } } TEST(SmallMap, Find) { TEST(SmallMap, Get) { { // Constant reference. const SmallMap map = ftl::init::map('a', 'A')('b', 'B')('c', 'C'); Loading @@ -172,14 +175,15 @@ TEST(SmallMap, Find) { EXPECT_EQ(d, 'D'); } { // Constant unary operation. // Immutable transform operation. const SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); EXPECT_EQ(map.get('c', [](char c) { return std::toupper(c); }), 'Z'); EXPECT_EQ(map.get('c').transform([](char c) { return std::toupper(c); }), 'Z'); } { // Mutable unary operation. // Mutable transform operation. SmallMap map = ftl::init::map('a', 'x')('b', 'y')('c', 'z'); EXPECT_TRUE(map.get('c', [](char& c) { c = std::toupper(c); })); EXPECT_EQ(map.get('c').transform(ftl::unit_fn([](char& c) { c = std::toupper(c); })), ftl::unit); EXPECT_EQ(map, SmallMap(ftl::init::map('c', 'Z')('b', 'y')('a', 'x'))); } Loading Loading @@ -247,7 +251,7 @@ TEST(SmallMap, TryReplace) { } { // Replacement arguments can refer to the replaced mapping. const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. Loading Loading @@ -292,7 +296,7 @@ TEST(SmallMap, EmplaceOrReplace) { } { // Replacement arguments can refer to the replaced mapping. const auto ref = map.get(2, [](const auto& s) { return s.str[0]; }); const auto ref = map.get(2).transform([](const String& s) { return s.str[0]; }); ASSERT_TRUE(ref); // Construct std::string from one character. Loading
services/surfaceflinger/SurfaceFlinger.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -3247,10 +3247,11 @@ void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; const auto opt = displayInputInfos.get(layer->getLayerStack(), [](const auto& info) -> Layer::InputDisplayArgs { return {&info.transform, info.isSecure}; const auto opt = displayInputInfos.get(layer->getLayerStack()) .transform([](const DisplayDevice::InputInfo& info) { return Layer::InputDisplayArgs{&info.transform, info.isSecure}; }); outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{}))); }); Loading