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