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