xref: /aosp_15_r20/frameworks/native/include/ftl/algorithm.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <algorithm>
20*38e8c45fSAndroid Build Coastguard Worker #include <functional>
21*38e8c45fSAndroid Build Coastguard Worker #include <utility>
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker #include <ftl/optional.h>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl {
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker // Determines if a container contains a value. This is a simplified version of the C++23
28*38e8c45fSAndroid Build Coastguard Worker // std::ranges::contains function.
29*38e8c45fSAndroid Build Coastguard Worker //
30*38e8c45fSAndroid Build Coastguard Worker //   const ftl::StaticVector vector = {1, 2, 3};
31*38e8c45fSAndroid Build Coastguard Worker //   assert(ftl::contains(vector, 1));
32*38e8c45fSAndroid Build Coastguard Worker //
33*38e8c45fSAndroid Build Coastguard Worker // TODO: Remove in C++23.
34*38e8c45fSAndroid Build Coastguard Worker template <typename Container, typename Value>
35*38e8c45fSAndroid Build Coastguard Worker auto contains(const Container& container, const Value& value) -> bool {
36*38e8c45fSAndroid Build Coastguard Worker   return std::find(container.begin(), container.end(), value) != container.end();
37*38e8c45fSAndroid Build Coastguard Worker }
38*38e8c45fSAndroid Build Coastguard Worker 
39*38e8c45fSAndroid Build Coastguard Worker // Adapter for std::find_if that converts the return value from iterator to optional.
40*38e8c45fSAndroid Build Coastguard Worker //
41*38e8c45fSAndroid Build Coastguard Worker //   const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
42*38e8c45fSAndroid Build Coastguard Worker //   assert(ftl::find_if(vector, [](const auto& str) { return str.front() == 'c'; }) == "cake"sv);
43*38e8c45fSAndroid Build Coastguard Worker //
44*38e8c45fSAndroid Build Coastguard Worker template <typename Container, typename Predicate, typename V = typename Container::value_type>
45*38e8c45fSAndroid Build Coastguard Worker constexpr auto find_if(const Container& container, Predicate&& predicate)
46*38e8c45fSAndroid Build Coastguard Worker     -> Optional<std::reference_wrapper<const V>> {
47*38e8c45fSAndroid Build Coastguard Worker   const auto it = std::find_if(std::cbegin(container), std::cend(container),
48*38e8c45fSAndroid Build Coastguard Worker                                std::forward<Predicate>(predicate));
49*38e8c45fSAndroid Build Coastguard Worker   if (it == std::cend(container)) return {};
50*38e8c45fSAndroid Build Coastguard Worker   return std::cref(*it);
51*38e8c45fSAndroid Build Coastguard Worker }
52*38e8c45fSAndroid Build Coastguard Worker 
53*38e8c45fSAndroid Build Coastguard Worker // Transformers for ftl::find_if on a map-like `Container` that contains key-value pairs.
54*38e8c45fSAndroid Build Coastguard Worker //
55*38e8c45fSAndroid Build Coastguard Worker //   const ftl::SmallMap map = ftl::init::map<int, ftl::StaticVector<std::string_view, 3>>(
56*38e8c45fSAndroid Build Coastguard Worker //       12, "snow"sv, "cone"sv)(13, "tiramisu"sv)(14, "upside"sv, "down"sv, "cake"sv);
57*38e8c45fSAndroid Build Coastguard Worker //
58*38e8c45fSAndroid Build Coastguard Worker //   using Map = decltype(map);
59*38e8c45fSAndroid Build Coastguard Worker //
60*38e8c45fSAndroid Build Coastguard Worker //   assert(14 == ftl::find_if(map, [](const auto& pair) {
61*38e8c45fSAndroid Build Coastguard Worker //                  return pair.second.size() == 3;
62*38e8c45fSAndroid Build Coastguard Worker //                }).transform(ftl::to_key<Map>));
63*38e8c45fSAndroid Build Coastguard Worker //
64*38e8c45fSAndroid Build Coastguard Worker //   const auto opt = ftl::find_if(map, [](const auto& pair) {
65*38e8c45fSAndroid Build Coastguard Worker //                      return pair.second.size() == 1;
66*38e8c45fSAndroid Build Coastguard Worker //                    }).transform(ftl::to_mapped_ref<Map>);
67*38e8c45fSAndroid Build Coastguard Worker //
68*38e8c45fSAndroid Build Coastguard Worker //   assert(opt);
69*38e8c45fSAndroid Build Coastguard Worker //   assert(opt->get() == ftl::StaticVector("tiramisu"sv));
70*38e8c45fSAndroid Build Coastguard Worker //
71*38e8c45fSAndroid Build Coastguard Worker template <typename Map, typename Pair = typename Map::value_type,
72*38e8c45fSAndroid Build Coastguard Worker           typename Key = typename Map::key_type>
73*38e8c45fSAndroid Build Coastguard Worker constexpr auto to_key(const Pair& pair) -> Key {
74*38e8c45fSAndroid Build Coastguard Worker   return pair.first;
75*38e8c45fSAndroid Build Coastguard Worker }
76*38e8c45fSAndroid Build Coastguard Worker 
77*38e8c45fSAndroid Build Coastguard Worker template <typename Map, typename Pair = typename Map::value_type,
78*38e8c45fSAndroid Build Coastguard Worker           typename Mapped = typename Map::mapped_type>
79*38e8c45fSAndroid Build Coastguard Worker constexpr auto to_mapped_ref(const Pair& pair) -> std::reference_wrapper<const Mapped> {
80*38e8c45fSAndroid Build Coastguard Worker   return std::cref(pair.second);
81*38e8c45fSAndroid Build Coastguard Worker }
82*38e8c45fSAndroid Build Coastguard Worker 
83*38e8c45fSAndroid Build Coastguard Worker // Combinator for ftl::Optional<T>::or_else when T is std::reference_wrapper<const V>. Given a
84*38e8c45fSAndroid Build Coastguard Worker // lambda argument that returns a `constexpr` value, ftl::static_ref<T> binds a reference to a
85*38e8c45fSAndroid Build Coastguard Worker // static T initialized to that constant.
86*38e8c45fSAndroid Build Coastguard Worker //
87*38e8c45fSAndroid Build Coastguard Worker //   const ftl::SmallMap map = ftl::init::map(13, "tiramisu"sv)(14, "upside-down cake"sv);
88*38e8c45fSAndroid Build Coastguard Worker //   assert("???"sv ==
89*38e8c45fSAndroid Build Coastguard Worker //          map.get(20).or_else(ftl::static_ref<std::string_view>([] { return "???"sv; }))->get());
90*38e8c45fSAndroid Build Coastguard Worker //
91*38e8c45fSAndroid Build Coastguard Worker //   using Map = decltype(map);
92*38e8c45fSAndroid Build Coastguard Worker //
93*38e8c45fSAndroid Build Coastguard Worker //   assert("snow cone"sv ==
94*38e8c45fSAndroid Build Coastguard Worker //          ftl::find_if(map, [](const auto& pair) { return pair.second.front() == 's'; })
95*38e8c45fSAndroid Build Coastguard Worker //              .transform(ftl::to_mapped_ref<Map>)
96*38e8c45fSAndroid Build Coastguard Worker //              .or_else(ftl::static_ref<std::string_view>([] { return "snow cone"sv; }))
97*38e8c45fSAndroid Build Coastguard Worker //              ->get());
98*38e8c45fSAndroid Build Coastguard Worker //
99*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename F>
static_ref(F && f)100*38e8c45fSAndroid Build Coastguard Worker constexpr auto static_ref(F&& f) {
101*38e8c45fSAndroid Build Coastguard Worker   return [f = std::forward<F>(f)] {
102*38e8c45fSAndroid Build Coastguard Worker     constexpr auto kInitializer = f();
103*38e8c45fSAndroid Build Coastguard Worker     static const T kValue = kInitializer;
104*38e8c45fSAndroid Build Coastguard Worker     return Optional(std::cref(kValue));
105*38e8c45fSAndroid Build Coastguard Worker   };
106*38e8c45fSAndroid Build Coastguard Worker }
107*38e8c45fSAndroid Build Coastguard Worker 
108*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl
109